Skip to content

Commit 7d477a3

Browse files
Make memory JSON-serializable by default; simplify conversation history; remove run-id result storage (#68)
* refactor: standard_agent memory serializability, removing using deque for the rolling window storing conversation history
1 parent 1a1d960 commit 7d477a3

3 files changed

Lines changed: 38 additions & 11 deletions

File tree

agents/standard_agent.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from __future__ import annotations
99

1010
from collections.abc import MutableMapping
11-
from collections import deque
1211
from agents.reasoner.base import BaseReasoner, ReasoningResult
1312
from agents.llm.base_llm import BaseLLM
1413
from agents.tools.base import JustInTimeToolingBase
@@ -61,7 +60,8 @@ def __init__(
6160
self.reasoner = reasoner
6261

6362
self.goal_preprocessor = goal_preprocessor
64-
self.memory.setdefault("conversation_history", deque(maxlen=conversation_history_window))
63+
self.conversation_history_window = conversation_history_window
64+
self.memory.setdefault("conversation_history", [])
6565

6666
self._state: AgentState = AgentState.READY
6767

@@ -77,19 +77,17 @@ def solve(self, goal: str) -> ReasoningResult:
7777
if self.goal_preprocessor:
7878
revised_goal, intervention_message = self.goal_preprocessor.process(goal, self.memory.get("conversation_history"))
7979
if intervention_message:
80-
self.memory["conversation_history"].append({ "goal": goal, "result": f"user intervention message: {intervention_message}"})
80+
self._record_interaction({"goal": goal, "result": f"user intervention message: {intervention_message}"})
8181
return ReasoningResult(success=False, final_answer=intervention_message)
8282
goal = revised_goal
8383

84-
self.memory[f"goal:{run_id}"] = goal
8584
self._state = AgentState.BUSY
8685

8786
try:
8887
result = self.reasoner.run(goal)
8988
result.final_answer = self.llm.prompt(_PROMPTS["summarize"].format(goal=goal, history=getattr(result, "transcript", "")))
9089

91-
self.memory[f"result:{run_id}"] = result
92-
self.memory["conversation_history"].append({"goal": goal, "result": result.final_answer})
90+
self._record_interaction({"goal": goal, "result": result.final_answer})
9391
self._state = AgentState.READY
9492

9593
duration_ms = int((time.perf_counter() - start_time) * 1000)
@@ -109,3 +107,9 @@ def solve(self, goal: str) -> ReasoningResult:
109107
except Exception:
110108
self._state = AgentState.NEEDS_ATTENTION
111109
raise
110+
111+
def _record_interaction(self, entry: dict) -> None:
112+
if self.conversation_history_window <= 0:
113+
return
114+
self.memory["conversation_history"].append(entry)
115+
self.memory["conversation_history"][:] = self.memory["conversation_history"][-self.conversation_history_window:]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "standard-agent"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
description = "A simple, modular library for building AI agents—with a composable core and plug‑in components."
55
requires-python = ">=3.11"
66
readme = "README.md"

tests/agents/test_standard_agent.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Any, Deque, Dict, List, Optional, Tuple
22

33
import pytest
4+
import json
45

56
from agents.standard_agent import StandardAgent, AgentState
67
from agents.reasoner.base import BaseReasoner, ReasoningResult
@@ -88,10 +89,6 @@ def test_agent_solve_sets_final_answer_from_summarizer_and_records_history(monke
8889
assert hist[-1]["goal"] == "find answer"
8990
assert hist[-1]["result"] == "SUMMARIZED"
9091

91-
# Goal and result stored with deterministic run id
92-
assert memory.get("goal:RUN123") == "find answer"
93-
assert isinstance(memory.get("result:RUN123"), ReasoningResult)
94-
9592

9693
def test_agent_uses_goal_preprocessor_and_returns_intervention_message(monkeypatch):
9794
_fixed_uuid4(monkeypatch, "RUNINT")
@@ -210,3 +207,29 @@ def test_agent_initial_state_is_ready():
210207
assert agent.state == AgentState.READY
211208

212209

210+
211+
def test_agent_memory_is_json_serializable(monkeypatch):
212+
llm = DummyLLM(text_queue=["S1", "S2"])
213+
tools = DummyTools()
214+
memory: Dict[str, Any] = DictMemory()
215+
agent = StandardAgent(llm=llm, tools=tools, memory=memory, reasoner=DummyReasoner(), conversation_history_window=2)
216+
217+
agent.solve("g1")
218+
agent.solve("g2")
219+
220+
dumped = json.dumps(agent.memory)
221+
assert isinstance(dumped, str)
222+
assert isinstance(agent.memory.get("conversation_history"), list)
223+
assert len(agent.memory["conversation_history"]) == 2
224+
225+
226+
def test_agent_conversation_history_disabled_window():
227+
llm = DummyLLM(text_queue=["S"]) # summarizer output
228+
tools = DummyTools()
229+
memory: Dict[str, Any] = DictMemory()
230+
agent = StandardAgent(llm=llm, tools=tools, memory=memory, reasoner=DummyReasoner(), conversation_history_window=0)
231+
232+
agent.solve("g1")
233+
234+
assert memory.get("conversation_history") == []
235+

0 commit comments

Comments
 (0)