New nodes (5):
- Relay: local message delivery between agents (outbox→inbox)
- ChatHistory: multi-turn conversation persistence across runs
- PromptTemplate: {a}/{b}/{c}/{d} variable substitution
- ConditionalRouter: keyword/regex routing with matched/unmatched outputs
- BatchSplitter: split text into numbered sections by delimiter
Fixed nodes (3):
- TextCombine: removed forceInput, text_a/text_b now typeable widgets
- Remember: removed forceInput on text, now typeable widget
- Send: removed forceInput on body, now typeable widget
Demo workflows (7):
1. Character Design - art director with memory for consistent characters
2. Novel Crafter - writer+editor dual-agent with Relay message delivery
3. Story to Video - director breaks story into scenes with BatchSplitter
4. Multi-Turn Chat - persistent conversation history across queue runs
5. Agent Debate - two agents argue via message passing (FOR vs AGAINST)
6. World Builder - game world with PromptTemplate for locations/characters
7. RAG Pipeline - store docs, search, answer with ConditionalRouter error handling
76 tests all passing (46 original + 30 new).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
94 lines
3.5 KiB
Python
94 lines
3.5 KiB
Python
"""Tests for AgentAZAll ComfyUI memory nodes (Remember, Recall, Note)."""
|
|
|
|
import pytest
|
|
|
|
from nodes.memory_nodes import AgentAZAll_Remember, AgentAZAll_Recall, AgentAZAll_Note
|
|
|
|
|
|
class TestRemember:
|
|
|
|
def test_remember_stores(self, agent_config):
|
|
"""Remember stores a new memory file."""
|
|
node = AgentAZAll_Remember()
|
|
(result,) = node.remember(agent_config, "The sky is blue.", "sky-color")
|
|
assert "sky-color" in result
|
|
|
|
def test_remember_appends(self, agent_config):
|
|
"""Remember appends to existing memory with same title."""
|
|
node = AgentAZAll_Remember()
|
|
node.remember(agent_config, "First observation.", "observations")
|
|
node.remember(agent_config, "Second observation.", "observations")
|
|
|
|
# Verify via recall
|
|
recall_node = AgentAZAll_Recall()
|
|
(results,) = recall_node.recall(agent_config, "observation")
|
|
assert "observation" in results.lower()
|
|
|
|
def test_remember_auto_title(self, agent_config):
|
|
"""Remember generates timestamp title when none provided."""
|
|
node = AgentAZAll_Remember()
|
|
(result,) = node.remember(agent_config, "Untitled memory.", "")
|
|
assert "Memory stored:" in result
|
|
|
|
|
|
class TestRecall:
|
|
|
|
def test_recall_empty(self, agent_config):
|
|
"""Recall returns 'no memories' when nothing stored."""
|
|
node = AgentAZAll_Recall()
|
|
(result,) = node.recall(agent_config, "anything")
|
|
assert "No memories" in result
|
|
|
|
def test_recall_with_query(self, agent_config):
|
|
"""Recall finds matching memories by query."""
|
|
remember = AgentAZAll_Remember()
|
|
remember.remember(agent_config, "Dragons have scales.", "dragon-facts")
|
|
remember.remember(agent_config, "Cats have whiskers.", "cat-facts")
|
|
|
|
node = AgentAZAll_Recall()
|
|
(result,) = node.recall(agent_config, "dragon")
|
|
assert "dragon" in result.lower()
|
|
assert "cat" not in result.lower()
|
|
|
|
def test_recall_all(self, agent_config):
|
|
"""Recall without query returns full memory index."""
|
|
remember = AgentAZAll_Remember()
|
|
remember.remember(agent_config, "Memory one.", "mem-1")
|
|
remember.remember(agent_config, "Memory two.", "mem-2")
|
|
|
|
node = AgentAZAll_Recall()
|
|
(result,) = node.recall(agent_config, "")
|
|
assert "mem-1" in result
|
|
assert "mem-2" in result
|
|
|
|
def test_recall_case_insensitive(self, agent_config):
|
|
"""Recall search is case-insensitive."""
|
|
remember = AgentAZAll_Remember()
|
|
remember.remember(agent_config, "UPPERCASE CONTENT", "upper")
|
|
|
|
node = AgentAZAll_Recall()
|
|
(result,) = node.recall(agent_config, "uppercase")
|
|
assert "upper" in result.lower()
|
|
|
|
|
|
class TestNote:
|
|
|
|
def test_note_write(self, agent_config):
|
|
"""Note writes content and returns it."""
|
|
node = AgentAZAll_Note()
|
|
(result,) = node.note(agent_config, "plot-outline", "Chapter 1: The beginning.")
|
|
assert "Chapter 1" in result
|
|
|
|
def test_note_read(self, agent_config):
|
|
"""Note reads previously written content."""
|
|
node = AgentAZAll_Note()
|
|
node.note(agent_config, "character-sheet", "Name: Elara\nClass: Mage")
|
|
(result,) = node.note(agent_config, "character-sheet", "")
|
|
assert "Elara" in result
|
|
|
|
def test_note_not_found(self, agent_config):
|
|
"""Note returns 'not found' for non-existent note."""
|
|
node = AgentAZAll_Note()
|
|
(result,) = node.note(agent_config, "nonexistent", "")
|
|
assert "not found" in result.lower()
|