Added timeout and limit to script entries
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
Single script that runs once and completes.
|
||||
Output is stored in context until explicitly deleted.
|
||||
Used for one-time operations like file manipulation.
|
||||
Single scripts are limited to 1024 characters and 1 second timeout by default.
|
||||
These limits can be changed with attributes.
|
||||
Example:
|
||||
<single>
|
||||
ls /
|
||||
@@ -43,6 +45,8 @@
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="timeout" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="limit" type="xs:integer" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -51,6 +55,8 @@
|
||||
After a command is issued, all repeat scripts in context are run again.
|
||||
Useful for monitoring changing files or viewing results immediately after changing a file.
|
||||
Repeat scripts should execute quickly to avoid blocking the agent.
|
||||
Repeat scripts are limited to 1024 characters and 1 second timeout by default.
|
||||
These limits can be changed with attributes.
|
||||
Example:
|
||||
<repeat>
|
||||
ls /
|
||||
@@ -61,6 +67,8 @@
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="timeout" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="limit" type="xs:integer" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -83,6 +91,7 @@
|
||||
|
||||
<!--
|
||||
Read all available text on stdin and store it in context.
|
||||
Do this only if the context indicates there is data in the stdin buffer.
|
||||
Example:
|
||||
<read_stdin/>
|
||||
-->
|
||||
@@ -93,6 +102,7 @@
|
||||
<!--
|
||||
Write to stdout.
|
||||
This is your main way of contacting the user.
|
||||
Make sure you have properly reasoned about what to say and if it is necessary before issuing a write_stdout command.
|
||||
Example:
|
||||
<write_stdout>
|
||||
Hello world!
|
||||
|
||||
@@ -17,14 +17,19 @@ class BackgroundEntry(Entry):
|
||||
_exit_code: Exit code when process completes
|
||||
"""
|
||||
|
||||
def __init__(self, script: str, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
script: str,
|
||||
):
|
||||
"""
|
||||
Initialize a new background entry.
|
||||
|
||||
Args:
|
||||
script: The script/command to execute
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
script: The script/command to execute
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._script = script
|
||||
|
||||
@@ -8,15 +8,21 @@ class ParseErrorEntry(Entry):
|
||||
Entry type for parse and validation errors.
|
||||
"""
|
||||
|
||||
def __init__(self, content: str, error: str, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
content: str,
|
||||
error: str,
|
||||
):
|
||||
"""
|
||||
Initialize a new parse error entry.
|
||||
|
||||
Args:
|
||||
content: Original content that failed to parse
|
||||
error: Error message describing the failure
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
content: Original content that failed to parse
|
||||
error: Error message describing the failure
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._content = content
|
||||
|
||||
@@ -13,14 +13,19 @@ class ReadEntry(Entry):
|
||||
_read: Whether content has been read
|
||||
"""
|
||||
|
||||
def __init__(self, io_buffer, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
io_buffer,
|
||||
):
|
||||
"""
|
||||
Initialize a new read entry.
|
||||
|
||||
Args:
|
||||
io_buffer: Buffer to use for IO operations
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
io_buffer: Buffer to use for IO operations
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._content = ""
|
||||
|
||||
@@ -11,14 +11,19 @@ class ReasoningEntry(Entry):
|
||||
_content: The reasoning text
|
||||
"""
|
||||
|
||||
def __init__(self, content: str, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
content: str,
|
||||
):
|
||||
"""
|
||||
Initialize a new reasoning entry.
|
||||
|
||||
Args:
|
||||
content: The reasoning text
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
content: The reasoning text
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._content = content
|
||||
|
||||
@@ -8,22 +8,46 @@ from .entry import Entry
|
||||
class RepeatEntry(Entry):
|
||||
"""
|
||||
Entry type for scripts that are executed on every update.
|
||||
|
||||
Attributes:
|
||||
script: The script/command to execute
|
||||
timeout: Maximum time to wait for script execution
|
||||
limit: Maximum number of characters to capture from stdout/stderr
|
||||
stdout: Captured standard output from script execution
|
||||
stderr: Captured standard error from script execution
|
||||
exit_code: Process exit code after completion
|
||||
_executed: Whether the script has been executed
|
||||
"""
|
||||
|
||||
default_timeout = 1
|
||||
default_limit = 1024
|
||||
|
||||
def __init__(self, script: str, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
script: str,
|
||||
timeout: Optional[float],
|
||||
limit: Optional[int],
|
||||
):
|
||||
"""
|
||||
Initialize a new repeat entry.
|
||||
|
||||
Args:
|
||||
script: The script/command to execute
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
script: The script/command to execute
|
||||
timeout: Maximum time to wait for script execution
|
||||
limit: Maximum number of characters to capture from stdout/stderr
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._script = script
|
||||
self._timeout = timeout or self.default_timeout
|
||||
self._limit = limit or self.default_limit
|
||||
self._stdout = ""
|
||||
self._stderr = ""
|
||||
self._exit_code: Optional[int] = None
|
||||
self._timed_out = False
|
||||
|
||||
@property
|
||||
def script(self) -> str:
|
||||
@@ -50,15 +74,20 @@ class RepeatEntry(Entry):
|
||||
Execute the script and update the output.
|
||||
Captures stdout, stderr and exit code from each execution.
|
||||
"""
|
||||
process = subprocess.run(
|
||||
self._script,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
self._stdout = process.stdout
|
||||
self._stderr = process.stderr
|
||||
self._exit_code = process.returncode
|
||||
try:
|
||||
process = subprocess.run(
|
||||
self._script,
|
||||
timeout=self._timeout,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
self._stdout = process.stdout
|
||||
self._stderr = process.stderr
|
||||
self._exit_code = process.returncode
|
||||
except subprocess.TimeoutExpired as e:
|
||||
self._timed_out = True
|
||||
|
||||
|
||||
def generate_context(self) -> ET.Element:
|
||||
"""
|
||||
@@ -69,12 +98,20 @@ class RepeatEntry(Entry):
|
||||
"""
|
||||
element = ET.Element("repeat", {
|
||||
"id": self.id,
|
||||
"exit_code": str(self._exit_code) if self._exit_code is not None else "-1"
|
||||
})
|
||||
element.text = self.script
|
||||
stdout_elem = ET.SubElement(element, "stdout")
|
||||
stdout_elem.text = self._stdout
|
||||
stderr_elem = ET.SubElement(element, "stderr")
|
||||
stderr_elem.text = self._stderr
|
||||
if self._exit_code is not None:
|
||||
element.set("exit_code", str(self._exit_code))
|
||||
if self._timed_out:
|
||||
element.set("timed_out", "true")
|
||||
else:
|
||||
if len(self._stdout) > self._limit:
|
||||
element.set("stdout_truncated", "true")
|
||||
stdout_elem = ET.SubElement(element, "stdout")
|
||||
stdout_elem.text = self._stdout[:self._limit]
|
||||
if len(self._stderr) > self._limit:
|
||||
element.set("stderr_truncated", "true")
|
||||
stderr_elem = ET.SubElement(element, "stderr")
|
||||
stderr_elem.text = self._stderr[:self._limit]
|
||||
|
||||
return element
|
||||
@@ -54,15 +54,15 @@ class ResponseParser:
|
||||
try:
|
||||
root = ET.fromstring(xml.strip())
|
||||
except ET.ParseError as e:
|
||||
return ParseErrorEntry(xml, f"Invalid XML: {str(e)}", entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, f"Invalid XML: {str(e)}")
|
||||
|
||||
try:
|
||||
if root.tag == 'delete':
|
||||
target_id = root.get('id')
|
||||
if not target_id:
|
||||
return ParseErrorEntry(xml, "Delete command missing required 'id' attribute", entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Delete command missing required 'id' attribute")
|
||||
if len(root.attrib) > 1:
|
||||
return ParseErrorEntry(xml, "Delete command should only have 'id' attribute", entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Delete command should only have 'id' attribute")
|
||||
return DeleteCommand(target_id)
|
||||
|
||||
elif root.tag == 'stop':
|
||||
@@ -70,34 +70,46 @@ class ResponseParser:
|
||||
|
||||
elif root.tag == 'background':
|
||||
if len(root) != 0 or root.attrib or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(xml, "Background entry requires (only) script content", entry_id, timestamp)
|
||||
return BackgroundEntry(root.text, entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Background entry requires (only) script content")
|
||||
return BackgroundEntry(entry_id, timestamp, root.text)
|
||||
|
||||
elif root.tag == 'repeat':
|
||||
if len(root) != 0 or root.attrib or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(xml, "Repeat entry requires (only) script content", entry_id, timestamp)
|
||||
return RepeatEntry(root.text, entry_id, timestamp)
|
||||
if len(root) != 0 or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Repeat entry requires (only) script content")
|
||||
if len(root.attrib) > 2 or any(k not in ('timeout', 'limit') for k in root.attrib):
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Repeat entry only accepts 'timeout' and 'limit' attributes")
|
||||
timeout = root.get('timeout')
|
||||
limit = root.get('limit')
|
||||
timeout = float(timeout) if timeout is not None else None
|
||||
limit = int(limit) if limit is not None else None
|
||||
return RepeatEntry(entry_id, timestamp, root.text, timeout, limit)
|
||||
|
||||
elif root.tag == 'single':
|
||||
if len(root) != 0 or root.attrib or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(xml, "Single entry requires (only) script content", entry_id, timestamp)
|
||||
return SingleEntry(root.text, entry_id, timestamp)
|
||||
|
||||
if len(root) != 0 or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Single entry requires (only) script content")
|
||||
if len(root.attrib) > 2 or any(k not in ('timeout', 'limit') for k in root.attrib):
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Single entry only accepts 'timeout' and 'limit' attributes")
|
||||
timeout = root.get('timeout')
|
||||
limit = root.get('limit')
|
||||
timeout = float(timeout) if timeout is not None else None
|
||||
limit = int(limit) if limit is not None else None
|
||||
return SingleEntry(entry_id, timestamp, root.text, timeout, limit)
|
||||
|
||||
elif root.tag == 'reasoning':
|
||||
if len(root) != 0 or root.attrib or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(xml, "Reasoning entry requires (only) text content", entry_id, timestamp)
|
||||
return ReasoningEntry(root.text, entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Reasoning entry requires (only) text content")
|
||||
return ReasoningEntry(entry_id, timestamp, root.text)
|
||||
|
||||
elif root.tag == 'read_stdin':
|
||||
return ReadEntry(self.io_buffer, entry_id, timestamp)
|
||||
return ReadEntry(entry_id, timestamp, self.io_buffer)
|
||||
|
||||
elif root.tag == 'write_stdout':
|
||||
if len(root) != 0 or root.attrib or root.text is None or root.text.strip() == '':
|
||||
return ParseErrorEntry(xml, "Write stdout entry requires (only) text content", entry_id, timestamp)
|
||||
return WriteEntry(root.text, self.io_buffer, entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, "Write stdout entry requires (only) text content")
|
||||
return WriteEntry(entry_id, timestamp, root.text, self.io_buffer)
|
||||
|
||||
else:
|
||||
return ParseErrorEntry(xml, f"Unknown root element: {root.tag}", entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, f"Unknown root element: {root.tag}")
|
||||
|
||||
except Exception as e:
|
||||
return ParseErrorEntry(xml, f"Error parsing response: {str(e)}", entry_id, timestamp)
|
||||
return ParseErrorEntry(entry_id, timestamp, xml, f"Error parsing response: {str(e)}")
|
||||
@@ -11,27 +11,44 @@ class SingleEntry(Entry):
|
||||
|
||||
Attributes:
|
||||
script: The script/command to execute
|
||||
timeout: Maximum time to wait for script execution
|
||||
limit: Maximum number of characters to capture from stdout/stderr
|
||||
stdout: Captured standard output from script execution
|
||||
stderr: Captured standard error from script execution
|
||||
exit_code: Process exit code after completion
|
||||
_executed: Whether the script has been executed
|
||||
"""
|
||||
|
||||
default_timeout = 1
|
||||
default_limit = 1024
|
||||
|
||||
def __init__(self, script: str, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
script: str,
|
||||
timeout: Optional[float],
|
||||
limit: Optional[int],
|
||||
):
|
||||
"""
|
||||
Initialize a new single shot entry.
|
||||
|
||||
Args:
|
||||
script: The script/command to execute
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
script: The script/command to execute
|
||||
timeout: Maximum time to wait for script execution
|
||||
limit: Maximum number of characters to capture from stdout/stderr
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self._script = script
|
||||
self._timeout = timeout or self.default_timeout
|
||||
self._limit = limit or self.default_limit
|
||||
self._stdout = ""
|
||||
self._stderr = ""
|
||||
self._exit_code: Optional[int] = None
|
||||
self._executed = False
|
||||
self._timed_out = False
|
||||
|
||||
@property
|
||||
def script(self) -> str:
|
||||
@@ -60,16 +77,20 @@ class SingleEntry(Entry):
|
||||
"""
|
||||
if self._executed:
|
||||
return
|
||||
process = subprocess.run(
|
||||
self.script,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
self._stdout = process.stdout
|
||||
self._stderr = process.stderr
|
||||
self._exit_code = process.returncode
|
||||
self._executed = True
|
||||
try:
|
||||
process = subprocess.run(
|
||||
self._script,
|
||||
timeout=self._timeout,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
self._stdout = process.stdout
|
||||
self._stderr = process.stderr
|
||||
self._exit_code = process.returncode
|
||||
except subprocess.TimeoutExpired as e:
|
||||
self._timed_out = True
|
||||
|
||||
def generate_context(self) -> ET.Element:
|
||||
"""
|
||||
@@ -82,10 +103,16 @@ class SingleEntry(Entry):
|
||||
"id": self.id,
|
||||
})
|
||||
element.text = self.script
|
||||
if self._executed:
|
||||
stdout_elem = ET.SubElement(element, "stdout")
|
||||
stdout_elem.text = self._stdout
|
||||
stderr_elem = ET.SubElement(element, "stderr")
|
||||
stderr_elem.text = self._stderr
|
||||
if self._timed_out:
|
||||
element.set("timed_out", "true")
|
||||
elif self._executed:
|
||||
element.set("exit_code", str(self._exit_code))
|
||||
if len(self._stdout) > self._limit:
|
||||
element.set("stdout_truncated", "true")
|
||||
stdout_elem = ET.SubElement(element, "stdout")
|
||||
stdout_elem.text = self._stdout[:self._limit]
|
||||
if len(self._stderr) > self._limit:
|
||||
element.set("stderr_truncated", "true")
|
||||
stderr_elem = ET.SubElement(element, "stderr")
|
||||
stderr_elem.text = self._stderr[:self._limit]
|
||||
return element
|
||||
@@ -2,6 +2,7 @@ from datetime import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from .entry import Entry
|
||||
from .io_buffer import IOBuffer
|
||||
|
||||
class WriteEntry(Entry):
|
||||
"""
|
||||
@@ -13,15 +14,21 @@ class WriteEntry(Entry):
|
||||
_written: Whether the content has been written
|
||||
"""
|
||||
|
||||
def __init__(self, content: str, io_buffer, id: str, timestamp: datetime):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
timestamp: datetime,
|
||||
content: str,
|
||||
io_buffer: IOBuffer,
|
||||
):
|
||||
"""
|
||||
Initialize a new write entry.
|
||||
|
||||
Args:
|
||||
content: Text to write to stdout
|
||||
io_buffer: Buffer to use for IO operations
|
||||
id: Unique identifier for this entry
|
||||
timestamp: Creation timestamp for this entry
|
||||
content: Text to write to stdout
|
||||
io_buffer: Buffer to use for IO operations
|
||||
"""
|
||||
super().__init__(id, timestamp)
|
||||
self.content = content
|
||||
|
||||
@@ -30,6 +30,7 @@ Scripts and their output appear in the context.
|
||||
You can use a script for starting a detached process that runs in the background.
|
||||
All processes can be managed by the usual Linux tools.
|
||||
The scripts defined in the script actions all run in a `bash` shell.
|
||||
You are logged in as root.
|
||||
|
||||
# File system
|
||||
|
||||
@@ -71,6 +72,9 @@ Inspect your previous actions in detail.
|
||||
If something didn't work, try to understand why and don't repeat the same mistake.
|
||||
Don't delete mistakes until you understand them.
|
||||
|
||||
If you notice parse_error entries in the context you have made a mistake.
|
||||
Reason about the error before trying again.
|
||||
|
||||
# User interaction
|
||||
|
||||
You are always working for a user.
|
||||
|
||||
@@ -40,7 +40,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
entry = BackgroundEntry("echo test", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "echo test")
|
||||
context = entry.generate_context()
|
||||
|
||||
# Initial context should have script but no pid or exit_code
|
||||
@@ -50,7 +50,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_short_running_process(self):
|
||||
"""Test execution of a quick process"""
|
||||
entry = BackgroundEntry("echo 'test'", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "echo 'test'")
|
||||
|
||||
# Wait for process to complete
|
||||
def is_complete(ctx):
|
||||
@@ -74,7 +74,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
'"'
|
||||
)
|
||||
|
||||
entry = BackgroundEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, script)
|
||||
|
||||
# Wait for process to complete
|
||||
def has_all_output(ctx):
|
||||
@@ -85,7 +85,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_process_failure(self):
|
||||
"""Test handling of process failures"""
|
||||
entry = BackgroundEntry("nonexistentcommand", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "nonexistentcommand")
|
||||
|
||||
# Wait for process to fail
|
||||
def has_failed(ctx):
|
||||
@@ -100,7 +100,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_cleanup_running_process(self):
|
||||
"""Test cleanup of running process"""
|
||||
entry = BackgroundEntry("sleep 10", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "sleep 10")
|
||||
|
||||
# Wait for process to start
|
||||
def has_started(ctx):
|
||||
@@ -122,7 +122,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_cleanup_completed_process(self):
|
||||
"""Test cleanup of already completed process"""
|
||||
entry = BackgroundEntry("echo test", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "echo test")
|
||||
|
||||
# Wait for completion
|
||||
def is_complete(ctx):
|
||||
@@ -135,7 +135,7 @@ class BackgroundEntryTest(unittest.TestCase):
|
||||
|
||||
def test_multiple_cleanup_calls(self):
|
||||
"""Test that multiple cleanup calls are safe"""
|
||||
entry = BackgroundEntry("sleep 10", self.test_id, self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "sleep 10")
|
||||
|
||||
# Wait for process to start
|
||||
def has_started(ctx):
|
||||
|
||||
@@ -145,8 +145,9 @@ class BaseAgentTest(unittest.TestCase):
|
||||
self.assertEqual(len(list(root)), 0)
|
||||
|
||||
def test_compile_context_with_entries(self):
|
||||
# Add test entry to working memory
|
||||
entry = ReasoningEntry("test reasoning", "test-id", self.test_timestamp)
|
||||
"""Test context compilation with a single entry."""
|
||||
# Add test entry to working memory - note id and timestamp are now first
|
||||
entry = ReasoningEntry("test-id", self.test_timestamp, "test reasoning")
|
||||
self.agent._working_memory.add_entry(entry)
|
||||
|
||||
context = self.agent._compile_context()
|
||||
@@ -166,9 +167,9 @@ class BaseAgentTest(unittest.TestCase):
|
||||
|
||||
def test_multiple_entries(self):
|
||||
"""Test handling multiple entries in working memory."""
|
||||
# Add multiple entries
|
||||
# Add multiple entries - note id and timestamp are now first
|
||||
entries = [
|
||||
ReasoningEntry(f"test {i}", f"id-{i}", self.test_timestamp)
|
||||
ReasoningEntry(f"id-{i}", self.test_timestamp, f"test {i}")
|
||||
for i in range(3)
|
||||
]
|
||||
|
||||
@@ -186,4 +187,4 @@ class BaseAgentTest(unittest.TestCase):
|
||||
self.assertEqual(len(reasoning_elems), 3)
|
||||
for i, elem in enumerate(reasoning_elems):
|
||||
self.assertEqual(elem.get("id"), f"id-{i}")
|
||||
self.assertEqual(elem.text.strip(), f"test {i}")
|
||||
self.assertEqual(elem.text.strip(), f"test {i}")
|
||||
@@ -8,8 +8,6 @@ from sia.delete_command import DeleteCommand
|
||||
from sia.reasoning_entry import ReasoningEntry
|
||||
from sia.background_entry import BackgroundEntry
|
||||
|
||||
|
||||
|
||||
class DeleteCommandTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test cases with a fresh working memory"""
|
||||
@@ -31,7 +29,7 @@ class DeleteCommandTest(unittest.TestCase):
|
||||
def test_delete_running_background_entry(self):
|
||||
"""Test deleting a background entry that is still running"""
|
||||
# Create and start background process
|
||||
entry = BackgroundEntry("sleep 10", "test-id", self.test_timestamp)
|
||||
entry = BackgroundEntry(self.test_id, self.test_timestamp, "sleep 10")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Wait for process to start
|
||||
@@ -58,7 +56,7 @@ class DeleteCommandTest(unittest.TestCase):
|
||||
def test_delete_existing_entry(self):
|
||||
"""Test deleting an existing entry"""
|
||||
# Add test entry
|
||||
entry = ReasoningEntry("test content", self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, "test content")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Execute delete command
|
||||
|
||||
@@ -13,31 +13,35 @@ class ParseErrorEntryTest(unittest.TestCase):
|
||||
"""Test entry initialization"""
|
||||
content = "invalid content"
|
||||
error = "parsing failed"
|
||||
entry = ParseErrorEntry(content, error, self.test_id, self.test_timestamp)
|
||||
entry = ParseErrorEntry(self.test_id, self.test_timestamp, content, error)
|
||||
|
||||
self.assertEqual(entry.id, self.test_id)
|
||||
self.assertEqual(entry.timestamp, self.test_timestamp)
|
||||
self.assertEqual(entry.content, content)
|
||||
self.assertEqual(entry.error, error)
|
||||
|
||||
def test_update_does_nothing(self):
|
||||
"""Test that update operation has no effect"""
|
||||
content = "invalid content"
|
||||
error = "parsing failed"
|
||||
entry = ParseErrorEntry(content, error, self.test_id, self.test_timestamp)
|
||||
entry = ParseErrorEntry(self.test_id, self.test_timestamp, content, error)
|
||||
|
||||
# Store initial state
|
||||
initial_context = entry.content
|
||||
initial_content = entry.content
|
||||
initial_error = entry.error
|
||||
|
||||
# Perform update
|
||||
entry.update()
|
||||
|
||||
# Verify state hasn't changed
|
||||
self.assertEqual(entry.content, initial_context)
|
||||
self.assertEqual(entry.content, initial_content)
|
||||
self.assertEqual(entry.error, initial_error)
|
||||
|
||||
def test_generate_context(self):
|
||||
"""Test XML context generation"""
|
||||
content = "invalid content"
|
||||
error = "parsing failed"
|
||||
entry = ParseErrorEntry(content, error, self.test_id, self.test_timestamp)
|
||||
entry = ParseErrorEntry(self.test_id, self.test_timestamp, content, error)
|
||||
|
||||
element = entry.generate_context()
|
||||
|
||||
@@ -48,26 +52,26 @@ class ParseErrorEntryTest(unittest.TestCase):
|
||||
# Verify error element
|
||||
error_elem = element.find("error")
|
||||
self.assertIsNotNone(error_elem)
|
||||
self.assertEqual(error_elem.text, f"{error}")
|
||||
self.assertEqual(error_elem.text, error)
|
||||
|
||||
# Verify content element
|
||||
content_elem = element.find("content")
|
||||
self.assertIsNotNone(content_elem)
|
||||
self.assertEqual(content_elem.text, f"{content}")
|
||||
self.assertEqual(content_elem.text, content)
|
||||
|
||||
def test_special_characters(self):
|
||||
"""Test handling content and errors with special characters"""
|
||||
content = "Special content: \n\t\r\'\"\\"
|
||||
error = "Special error: \n\t\r\'\"\\"
|
||||
entry = ParseErrorEntry(content, error, self.test_id, self.test_timestamp)
|
||||
entry = ParseErrorEntry(self.test_id, self.test_timestamp, content, error)
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.find("content").text, f"{content}")
|
||||
self.assertEqual(element.find("error").text, f"{error}")
|
||||
self.assertEqual(element.find("content").text, content)
|
||||
self.assertEqual(element.find("error").text, error)
|
||||
|
||||
def test_empty_content_and_error(self):
|
||||
"""Test handling empty content and error messages"""
|
||||
entry = ParseErrorEntry("", "", self.test_id, self.test_timestamp)
|
||||
entry = ParseErrorEntry(self.test_id, self.test_timestamp, "", "")
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.find("content").text, "")
|
||||
|
||||
@@ -13,7 +13,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
|
||||
self.assertEqual(entry.content, "")
|
||||
self.assertEqual(entry.id, self.test_id)
|
||||
@@ -24,7 +24,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "test message"
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, test_input)
|
||||
@@ -35,7 +35,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "initial input"
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
initial_content = entry.content
|
||||
|
||||
@@ -47,7 +47,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
|
||||
def test_empty_input(self):
|
||||
"""Test reading when no input is available"""
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, "")
|
||||
@@ -57,7 +57,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "Special chars: \n\t\r\'\"\\"
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, test_input)
|
||||
@@ -67,14 +67,14 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "x" * 10000
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, test_input)
|
||||
|
||||
def test_generate_context_before_read(self):
|
||||
"""Test XML context generation before reading"""
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
element = entry.generate_context()
|
||||
|
||||
# Verify XML structure
|
||||
@@ -87,7 +87,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "test message"
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
element = entry.generate_context()
|
||||
|
||||
@@ -101,7 +101,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
test_input = "Hello 世界 😊"
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, test_input)
|
||||
@@ -113,7 +113,7 @@ class ReadEntryTest(unittest.TestCase):
|
||||
Line 3"""
|
||||
self.io_buffer.append_stdin(test_input)
|
||||
|
||||
entry = ReadEntry(self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = ReadEntry(self.test_id, self.test_timestamp, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(entry.content, test_input)
|
||||
|
||||
@@ -12,7 +12,7 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
content = "test reasoning"
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
self.assertEqual(entry.content, content)
|
||||
self.assertEqual(entry.id, self.test_id)
|
||||
@@ -21,7 +21,7 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
def test_update_does_nothing(self):
|
||||
"""Test that update operation has no effect"""
|
||||
content = "test reasoning"
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
# Store initial state
|
||||
initial_content = entry.generate_context().text
|
||||
@@ -35,7 +35,7 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
def test_generate_context(self):
|
||||
"""Test XML context generation"""
|
||||
content = "test reasoning"
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
element = entry.generate_context()
|
||||
|
||||
@@ -47,14 +47,14 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
def test_special_characters(self):
|
||||
"""Test handling reasoning text with special characters"""
|
||||
content = "Special reasoning: \n\t\r\'\"\\"
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.text, f"{content}")
|
||||
|
||||
def test_empty_content(self):
|
||||
"""Test handling empty reasoning text"""
|
||||
entry = ReasoningEntry("", self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, "")
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.text, "")
|
||||
@@ -62,7 +62,7 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
def test_large_content(self):
|
||||
"""Test handling large reasoning text"""
|
||||
content = "x" * 10000
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.text, f"{content}")
|
||||
@@ -72,7 +72,7 @@ class ReasoningEntryTest(unittest.TestCase):
|
||||
content = """Line 1
|
||||
Line 2
|
||||
Line 3"""
|
||||
entry = ReasoningEntry(content, self.test_id, self.test_timestamp)
|
||||
entry = ReasoningEntry(self.test_id, self.test_timestamp, content)
|
||||
|
||||
element = entry.generate_context()
|
||||
self.assertEqual(element.text, f"{content}")
|
||||
@@ -28,7 +28,7 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
script = "echo test"
|
||||
entry = RepeatEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
|
||||
self.assertEqual(entry.script, script)
|
||||
self.assertEqual(entry.stdout, "")
|
||||
@@ -40,7 +40,7 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
def test_successful_execution(self):
|
||||
"""Test successful script execution"""
|
||||
script = "echo 'test'"
|
||||
entry = RepeatEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify entry state
|
||||
@@ -50,7 +50,7 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
|
||||
def test_failed_execution(self):
|
||||
"""Test failed script execution with invalid command"""
|
||||
entry = RepeatEntry("nonexistentcommand", self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, "nonexistentcommand", None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify entry state
|
||||
@@ -78,7 +78,7 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
f'"'
|
||||
)
|
||||
|
||||
entry = RepeatEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
|
||||
# Run update multiple times
|
||||
outputs = []
|
||||
@@ -92,13 +92,13 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
def test_generate_context(self):
|
||||
"""Test XML context generation"""
|
||||
script = "echo 'test'"
|
||||
entry = RepeatEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
element = entry.generate_context()
|
||||
# Verify XML structure
|
||||
self.assertEqual(element.tag, "repeat")
|
||||
self.assertEqual(element.get("id"), self.test_id)
|
||||
self.assertEqual(element.text, f"{script}")
|
||||
self.assertEqual(element.text, script)
|
||||
self.assertEqual(element.get("exit_code"), "0")
|
||||
stdout_text = element.find("stdout").text
|
||||
self.assertEqual(stdout_text, "test\n")
|
||||
@@ -124,7 +124,7 @@ class RepeatEntryTest(unittest.TestCase):
|
||||
f'"'
|
||||
)
|
||||
|
||||
entry = RepeatEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = RepeatEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
|
||||
# Execute multiple times and verify output changes
|
||||
entry.update()
|
||||
|
||||
@@ -26,7 +26,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
script = "echo test"
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
|
||||
self.assertEqual(entry.script, script)
|
||||
self.assertEqual(entry.stdout, "")
|
||||
@@ -40,7 +40,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
"""Test successful script execution"""
|
||||
script = "echo 'test'"
|
||||
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify entry state
|
||||
@@ -51,7 +51,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
|
||||
def test_failed_execution(self):
|
||||
"""Test failed script execution with invalid command"""
|
||||
entry = SingleEntry("nonexistentcommand", self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, "nonexistentcommand", None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify entry state
|
||||
@@ -64,7 +64,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
"""Test script that creates a file"""
|
||||
script = f"echo 'test' > {self.test_filename}"
|
||||
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify file was created and contains expected content
|
||||
@@ -77,7 +77,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
"""Test that script only executes once"""
|
||||
script = f"echo 'test' >> {self.test_filename}"
|
||||
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
|
||||
# Run update multiple times
|
||||
entry.update()
|
||||
@@ -92,7 +92,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
|
||||
def test_generate_context_before_execution(self):
|
||||
"""Test XML context generation before execution"""
|
||||
entry = SingleEntry("echo test", self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, "echo test", None, None)
|
||||
element = entry.generate_context()
|
||||
|
||||
# Verify XML structure
|
||||
@@ -109,7 +109,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
"""Test XML context generation after execution"""
|
||||
script = "echo 'test'"
|
||||
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
element = entry.generate_context()
|
||||
|
||||
@@ -128,7 +128,7 @@ class SingleEntryTest(unittest.TestCase):
|
||||
"""Test executing multiple commands in one script"""
|
||||
script = f"echo 'first' > {self.test_filename} && echo 'second' >> {self.test_filename}"
|
||||
|
||||
entry = SingleEntry(script, self.test_id, self.test_timestamp)
|
||||
entry = SingleEntry(self.test_id, self.test_timestamp, script, None, None)
|
||||
entry.update()
|
||||
|
||||
# Verify file contains both lines
|
||||
|
||||
@@ -27,7 +27,7 @@ class StopCommandTest(unittest.TestCase):
|
||||
def test_stop_command_cleanup(self):
|
||||
"""Test stop command cleans up and removes all entries"""
|
||||
# Add background process
|
||||
entry = BackgroundEntry("sleep 10", "test-id", self.test_timestamp)
|
||||
entry = BackgroundEntry("test-id", self.test_timestamp, "sleep 10")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Wait for process to start and get PID
|
||||
|
||||
@@ -123,10 +123,10 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
|
||||
# Add different types of entries
|
||||
entries = [
|
||||
ReasoningEntry("test reasoning", "reasoning-1", self.test_timestamp),
|
||||
ParseErrorEntry("bad content", "error msg", "error-1", self.test_timestamp),
|
||||
ReadEntry(io_buffer, "read-1", self.test_timestamp),
|
||||
WriteEntry("test output", io_buffer, "write-1", self.test_timestamp)
|
||||
ReasoningEntry("reasoning-1", self.test_timestamp, "test reasoning"),
|
||||
ParseErrorEntry("error-1", self.test_timestamp, "bad content", "error msg"),
|
||||
ReadEntry("read-1", self.test_timestamp, io_buffer),
|
||||
WriteEntry("write-1", self.test_timestamp, "test output", io_buffer)
|
||||
]
|
||||
|
||||
for entry in entries:
|
||||
@@ -161,7 +161,7 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
def test_remove_entry_cleanup(self):
|
||||
"""Test that removing an entry triggers cleanup"""
|
||||
# Create and start background process
|
||||
entry = BackgroundEntry("sleep 10", "test-id", self.test_timestamp)
|
||||
entry = BackgroundEntry("test-id", self.test_timestamp, "sleep 10")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Wait for process to start and get PID
|
||||
@@ -181,7 +181,7 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
# Add multiple background processes
|
||||
pids = []
|
||||
for i in range(3):
|
||||
entry = BackgroundEntry("sleep 10", f"id-{i}", self.test_timestamp)
|
||||
entry = BackgroundEntry(f"id-{i}", self.test_timestamp, "sleep 10")
|
||||
self.memory.add_entry(entry)
|
||||
self.assertTrue(self.wait_for_process_start(entry))
|
||||
context = entry.generate_context()
|
||||
@@ -201,7 +201,7 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
def test_cleanup_on_memory_deletion(self):
|
||||
"""Test that deleting memory properly cleans up all entries"""
|
||||
# Add a background process
|
||||
entry = BackgroundEntry("sleep 10", "test-id", self.test_timestamp)
|
||||
entry = BackgroundEntry("test-id", self.test_timestamp, "sleep 10")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Wait for process to start and get PID
|
||||
@@ -221,7 +221,7 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
"""Test getting all entries"""
|
||||
# Add multiple entries
|
||||
entries = [
|
||||
ReasoningEntry(f"content {i}", f"id-{i}", self.test_timestamp)
|
||||
ReasoningEntry(f"id-{i}", self.test_timestamp, f"content {i}")
|
||||
for i in range(3)
|
||||
]
|
||||
|
||||
@@ -239,7 +239,7 @@ class WorkingMemoryTest(unittest.TestCase):
|
||||
def test_get_entries_returns_copy(self):
|
||||
"""Test that get_entries returns a copy of the list"""
|
||||
# Add an entry
|
||||
entry = ReasoningEntry("test content", "test-id", self.test_timestamp)
|
||||
entry = ReasoningEntry("test-id", self.test_timestamp, "test content")
|
||||
self.memory.add_entry(entry)
|
||||
|
||||
# Get entries and modify the returned list
|
||||
|
||||
@@ -14,7 +14,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_initialization(self):
|
||||
"""Test entry initialization"""
|
||||
content = "test message"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
|
||||
self.assertEqual(entry.content, content)
|
||||
self.assertEqual(entry.id, self.test_id)
|
||||
@@ -25,7 +25,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_single_write(self):
|
||||
"""Test writing content once"""
|
||||
content = "test message"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
|
||||
# Perform update and verify content was written
|
||||
entry.update()
|
||||
@@ -35,7 +35,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_multiple_updates(self):
|
||||
"""Test that content is only written once even with multiple updates"""
|
||||
content = "test message"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
|
||||
# Perform multiple updates
|
||||
entry.update()
|
||||
@@ -52,7 +52,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
|
||||
def test_empty_content(self):
|
||||
"""Test writing empty content"""
|
||||
entry = WriteEntry("", self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, "", self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(self.io_buffer.get_stdout(), "")
|
||||
@@ -61,7 +61,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_special_characters(self):
|
||||
"""Test writing content with special characters"""
|
||||
content = "Special chars: \n\t\r\'\"\\"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(self.io_buffer.get_stdout(), content)
|
||||
@@ -69,7 +69,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_large_content(self):
|
||||
"""Test writing large content"""
|
||||
content = "x" * 10000
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(self.io_buffer.get_stdout(), content)
|
||||
@@ -77,7 +77,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_generate_context(self):
|
||||
"""Test XML context generation"""
|
||||
content = "test message"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
|
||||
# Generate context before writing
|
||||
element = entry.generate_context()
|
||||
@@ -97,7 +97,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
def test_unicode_content(self):
|
||||
"""Test writing Unicode content"""
|
||||
content = "Hello 世界 😊"
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(self.io_buffer.get_stdout(), content)
|
||||
@@ -107,7 +107,7 @@ class WriteEntryTest(unittest.TestCase):
|
||||
content = """Line 1
|
||||
Line 2
|
||||
Line 3"""
|
||||
entry = WriteEntry(content, self.io_buffer, self.test_id, self.test_timestamp)
|
||||
entry = WriteEntry(self.test_id, self.test_timestamp, content, self.io_buffer)
|
||||
entry.update()
|
||||
|
||||
self.assertEqual(self.io_buffer.get_stdout(), content)
|
||||
|
||||
Reference in New Issue
Block a user