From b6c1a95abda4bfb74575eb355d2080f02f6dfe5a Mon Sep 17 00:00:00 2001 From: geens Date: Sun, 24 Nov 2024 18:00:27 +0100 Subject: [PATCH] Added memory editing functionality --- sia/entry/entry_factory.py | 10 +- sia/entry/read_entry.py | 8 + sia/entry/repeat_entry.py | 8 +- sia/entry/single_entry.py | 1 + sia/entry/write_entry.py | 8 + sia/web/api.py | 1 - sia/working_memory.py | 9 +- .../editors/BackgroundEntryEditor.jsx | 124 +++++++++++++ web/src/components/editors/MemoryEditor.jsx | 145 ++++++++++++---- .../editors/ParseErrorEntryEditor.jsx | 53 ++++++ .../components/editors/ReadEntryEditor.jsx | 54 ++++++ .../editors/ReasoningEntryEditor.jsx | 40 +++++ .../components/editors/RepeatEntryEditor.jsx | 164 ++++++++++++++++++ .../components/editors/SingleEntryEditor.jsx | 62 +++++-- .../components/editors/WriteEntryEditor.jsx | 54 ++++++ 15 files changed, 688 insertions(+), 53 deletions(-) create mode 100644 web/src/components/editors/BackgroundEntryEditor.jsx create mode 100644 web/src/components/editors/ParseErrorEntryEditor.jsx create mode 100644 web/src/components/editors/ReadEntryEditor.jsx create mode 100644 web/src/components/editors/ReasoningEntryEditor.jsx create mode 100644 web/src/components/editors/RepeatEntryEditor.jsx create mode 100644 web/src/components/editors/WriteEntryEditor.jsx diff --git a/sia/entry/entry_factory.py b/sia/entry/entry_factory.py index 8d6e453..1b045e9 100644 --- a/sia/entry/entry_factory.py +++ b/sia/entry/entry_factory.py @@ -54,7 +54,7 @@ class EntryFactory: if "script" in data: entry.script = data["script"] if "timeout" in data: - entry.timeout = float(data["timeout"]) if data["timeout"] else None + entry.timeout = float(data["timeout"]) if data["timeout"] is not None else None if "limit" in data: entry.limit = int(data["limit"]) if data["limit"] else None if "stdout" in data: @@ -62,7 +62,7 @@ class EntryFactory: if "stderr" in data: entry.stderr = data["stderr"] if "exit_code" in data: - entry.exit_code = int(data["exit_code"]) if data["exit_code"] else None + entry.exit_code = int(data["exit_code"]) if data["exit_code"] is not None else None if "executed" in data: entry.executed = bool(data["executed"]) if "timed_out" in data: @@ -72,7 +72,7 @@ class EntryFactory: if "script" in data: entry.script = data["script"] if "timeout" in data: - entry.timeout = float(data["timeout"]) if data["timeout"] else None + entry.timeout = float(data["timeout"]) if data["timeout"] is not None else None if "limit" in data: entry.limit = int(data["limit"]) if data["limit"] else None if "stdout" in data: @@ -80,7 +80,7 @@ class EntryFactory: if "stderr" in data: entry.stderr = data["stderr"] if "exit_code" in data: - entry.exit_code = int(data["exit_code"]) if data["exit_code"] else None + entry.exit_code = int(data["exit_code"]) if data["exit_code"] is not None else None if "executed" in data: entry.executed = bool(data["executed"]) if "timed_out" in data: @@ -94,7 +94,7 @@ class EntryFactory: if "stderr" in data: entry.stderr = data["stderr"] if "exit_code" in data: - entry.exit_code = int(data["exit_code"]) if data["exit_code"] else None + entry.exit_code = int(data["exit_code"]) if data["exit_code"] is not None else None elif isinstance(entry, ParseErrorEntry): if "content" in data: diff --git a/sia/entry/read_entry.py b/sia/entry/read_entry.py index 9fb2f50..1a5d8ef 100644 --- a/sia/entry/read_entry.py +++ b/sia/entry/read_entry.py @@ -34,6 +34,14 @@ class ReadEntry(Entry): self.content = self._io_buffer.read() self.read = True self.notify_change() + + def reset(self) -> None: + """ + Reset the entry state to its initial state. + """ + self.read = False + self.content = "" + self.notify_change() def generate_context(self) -> ET.Element: """ diff --git a/sia/entry/repeat_entry.py b/sia/entry/repeat_entry.py index a9ad12f..ecd1cde 100644 --- a/sia/entry/repeat_entry.py +++ b/sia/entry/repeat_entry.py @@ -53,9 +53,9 @@ class RepeatEntry(Entry): self.stdout = process.stdout self.stderr = process.stderr self.exit_code = process.returncode - self._timed_out = False + self.timed_out = False except subprocess.TimeoutExpired as e: - self._timed_out = True + self.timed_out = True self.notify_change() def generate_context(self) -> ET.Element: @@ -69,7 +69,7 @@ class RepeatEntry(Entry): if self.timeout: element.set("timeout", str(self.timeout)) element.text = self.script - if self._timed_out: + if self.timed_out: element.set("timed_out", "true") elif self.exit_code is not None: element.set("exit_code", str(self.exit_code)) @@ -101,5 +101,5 @@ class RepeatEntry(Entry): "stdout": self.stdout, "stderr": self.stderr, "exit_code": self.exit_code, - "timed_out": self._timed_out + "timed_out": self.timed_out } diff --git a/sia/entry/single_entry.py b/sia/entry/single_entry.py index 15b10b0..eb965c6 100644 --- a/sia/entry/single_entry.py +++ b/sia/entry/single_entry.py @@ -45,6 +45,7 @@ class SingleEntry(Entry): self.stdout = "" self.stderr = "" self.exit_code = None + self.notify_change() def update(self) -> None: """ diff --git a/sia/entry/write_entry.py b/sia/entry/write_entry.py index e32f1c3..9c8250a 100644 --- a/sia/entry/write_entry.py +++ b/sia/entry/write_entry.py @@ -36,6 +36,13 @@ class WriteEntry(Entry): self._io_buffer.write(self.content) self.written = True self.notify_change() + + def reset(self) -> None: + """ + Reset the entry state to its initial state. + """ + self.written = False + self.notify_change() def generate_context(self) -> ET.Element: """ @@ -56,4 +63,5 @@ class WriteEntry(Entry): "type": "write", "id": self.id, "content": self.content, + "written": self.written, } diff --git a/sia/web/api.py b/sia/web/api.py index 8767865..9ccc64f 100644 --- a/sia/web/api.py +++ b/sia/web/api.py @@ -240,7 +240,6 @@ class Api: if not entry: return web.Response(status=404, text="Entry not found") entry.reset() - entry.notify_change() return web.Response(status=200) async def _update_entry(self, request: web.Request) -> web.Response: diff --git a/sia/working_memory.py b/sia/working_memory.py index c34392a..a87a8ff 100644 --- a/sia/working_memory.py +++ b/sia/working_memory.py @@ -29,6 +29,7 @@ class WorkingMemory: def _notify_change(self) -> None: """Notify all handlers of working memory changes.""" + self._sort_entries() for handler in self._change_handlers: handler() @@ -38,6 +39,10 @@ class WorkingMemory: self._changed_during_update.add(entry) else: self._notify_change() + + def _sort_entries(self) -> None: + """Sort entries by ID in chronological order.""" + self._entries.sort(key=lambda x: x.id) def add_entry(self, entry: Entry) -> None: """ @@ -50,6 +55,7 @@ class WorkingMemory: raise TypeError("Entry must be an instance of Entry class") entry.add_change_handler(self._handle_entry_change) self._entries.append(entry) + self._sort_entries() self._notify_change() def remove_entry(self, id: str) -> None: @@ -64,6 +70,7 @@ class WorkingMemory: if entry is not None: entry.cleanup() self._entries = [e for e in self._entries if e.id != id] + self._sort_entries() self._notify_change() def clear(self) -> None: @@ -101,7 +108,7 @@ class WorkingMemory: Get all entries in working memory. Returns: - List[Entry]: List of all entries + List[Entry]: List of all entries in chronological order """ return self._entries.copy() diff --git a/web/src/components/editors/BackgroundEntryEditor.jsx b/web/src/components/editors/BackgroundEntryEditor.jsx new file mode 100644 index 0000000..2036425 --- /dev/null +++ b/web/src/components/editors/BackgroundEntryEditor.jsx @@ -0,0 +1,124 @@ +import { BaseEntryEditor } from './BaseEntryEditor'; + +const CreateForm = ({ formData, setFormData }) => ( + <> +
+ +