Stateful AI agents with editable memory blocks and persistent storage
Project description
Asterix!
Stateful AI agents with editable memory blocks and persistent storage.
⚠️ EARLY DEVELOPMENT - NOT READY FOR PRODUCTION YET
This library is under active development.
Asterix is a lightweight Python library for building AI agents that can remember, learn, and persist their state across sessions. No servers required - just pip install and start building.
✨ Features
- 🧠 Editable Memory Blocks - Agents can read and write their own memory via built-in tools
- 💾 Persistent Storage - State saves across sessions (JSON/SQLite backends)
- 🔍 Semantic Search - Qdrant Cloud integration for long-term memory retrieval
- 🛠️ Tool System - Easy decorator pattern for custom capabilities
- 🔄 Multi-Model Support - Works with Groq, OpenAI, and extensible to others
- 📦 No Server Required - Pure Python library, runs anywhere
🚀 Quick Start
Installation
pip install asterix-agent
Or with UV (faster):
uv pip install asterix-agent
Basic Usage
from asterix import Agent, BlockConfig
# Create an agent with custom memory blocks
agent = Agent(
blocks={
"task": BlockConfig(size=1500, priority=1),
"notes": BlockConfig(size=1000, priority=2)
},
model="groq/llama-3.3-70b-versatile"
)
# Chat with your agent
response = agent.chat("Hello! Remember that I prefer Python over JavaScript.")
print(response)
# Agent automatically updates its memory
# Memory persists across conversations
Add Custom Tools
@agent.tool(name="read_file", description="Read a file from disk")
def read_file(filepath: str) -> str:
with open(filepath, 'r') as f:
return f.read()
# Now your agent can read files
response = agent.chat("Read config.yaml and summarize the settings")
Save & Load State
# Save agent state
agent.save_state()
# Later session - load previous state
agent = Agent.load_state("agent_id")
agent.chat("What were we discussing?") # Remembers everything!
📚 Configuration
Environment Variables
Create a .env file in your project root:
# LLM Provider (at least one required)
GROQ_API_KEY=your-groq-api-key
OPENAI_API_KEY=your-openai-api-key
# Vector Storage (required)
QDRANT_URL=https://your-cluster.cloud.qdrant.io:6333
QDRANT_API_KEY=your-qdrant-api-key
# Optional
ASTERIX_STATE_DIR=./agent_states
ASTERIX_LOG_LEVEL=INFO
YAML Configuration (Optional)
# agent_config.yaml
agent:
model: "groq/llama-3.3-70b-versatile"
temperature: 0.1
max_tokens: 1000
max_heartbeat_steps: 10
blocks:
task:
size: 1500
priority: 1
description: "Current task and progress"
notes:
size: 1000
priority: 2
description: "Important notes and reminders"
storage:
qdrant_url: "${QDRANT_URL}"
qdrant_api_key: "${QDRANT_API_KEY}"
state_backend: "json"
state_dir: "./agent_states"
Load from YAML:
agent = Agent.from_yaml("agent_config.yaml")
🧠 Memory System
Built-in Memory Tools
Agents have 5 built-in tools for managing their memory:
core_memory_append- Add content to a memory blockcore_memory_replace- Replace content in a memory blockarchival_memory_insert- Store information in Qdrant for long-term retrievalarchival_memory_search- Search archived memories semanticallyconversation_search- Search conversation history
These tools are called automatically by the agent when needed.
Memory Blocks
Configure memory blocks with custom sizes and priorities:
blocks = {
"task": BlockConfig(
size=2000, # Max tokens before eviction
priority=1, # Lower = evicted first
description="Current task context"
),
"user_prefs": BlockConfig(
size=500,
priority=5, # High priority = rarely evicted
description="User preferences and settings"
)
}
Automatic Memory Management
When a block exceeds its token limit:
- Content is summarized by LLM
- Full content archived in Qdrant
- Block replaced with summary
- Original retrievable via semantic search
🛠️ Custom Tools
Register custom tools using the decorator pattern:
from asterix import Agent
agent = Agent(...)
@agent.tool(
name="execute_shell",
description="Run a shell command and return output"
)
def execute_shell(command: str) -> str:
import subprocess
result = subprocess.run(command, shell=True, capture_output=True, text=True)
return result.stdout
@agent.tool(name="search_web")
def search_web(query: str) -> str:
# Your web search implementation
return "Search results..."
# Agent can now use these tools
response = agent.chat("List all Python files in the current directory")
💾 State Persistence
Save & Load
# Save agent state to disk
agent.save_state() # Saves to ./agent_states/{agent_id}.json
# Load from disk
agent = Agent.load_state("agent_id")
# Custom state directory
agent = Agent(..., state_dir="./my_agents")
agent.save_state()
State Backends
# JSON (default)
agent = Agent(..., state_backend="json")
# SQLite (better for many agents)
agent = Agent(..., state_backend="sqlite", state_db="agents.db")
# Custom backend
from asterix.storage import StateBackend
class RedisBackend(StateBackend):
def save(self, agent_id: str, state: dict): ...
def load(self, agent_id: str) -> dict: ...
agent = Agent(..., state_backend=RedisBackend())
📖 Examples
CLI Agent with File Operations
from asterix import Agent, BlockConfig
import os
agent = Agent(
blocks={
"current_task": BlockConfig(size=2000, priority=1),
"file_context": BlockConfig(size=3000, priority=2)
},
model="groq/llama-3.3-70b-versatile"
)
@agent.tool(name="list_files")
def list_files(directory: str = ".") -> str:
files = os.listdir(directory)
return "\n".join(files)
@agent.tool(name="read_file")
def read_file(filepath: str) -> str:
with open(filepath, 'r') as f:
return f.read()
# Use the agent
agent.chat("List all Python files and review main.py for potential issues")
Multi-Agent System
# Orchestrator agent
main_agent = Agent(
agent_id="orchestrator",
blocks={"plan": BlockConfig(size=1500)},
model="groq/llama-3.3-70b-versatile"
)
# Specialized agents
code_reviewer = Agent(
agent_id="reviewer",
blocks={"code": BlockConfig(size=3000)},
model="groq/llama-3.3-70b-versatile"
)
# Coordination
task = "Review auth.py for security issues"
plan = main_agent.chat(f"Break down: {task}")
review = code_reviewer.chat(f"Execute: {plan}")
summary = main_agent.chat(f"Summarize: {review}")
🔧 Advanced Usage
Direct Memory Access
# Get all memory blocks
memory = agent.get_memory()
print(memory["task"])
# Update memory manually
agent.update_memory("task", "New content")
# Search archival memory
results = agent.search_archival("user preferences", k=5)
for result in results:
print(f"Score: {result.score}, Text: {result.summary}")
Heartbeat Control (Advanced)
# Manual heartbeat loop control
controller = agent.create_heartbeat_controller()
for step in controller.run("Complex multi-step task"):
if step.needs_tool_execution:
# Custom tool execution logic
results = my_custom_executor(step.tool_calls)
controller.submit_tool_results(results)
elif step.is_complete:
response = step.get_response()
break
🧪 Testing
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# With coverage
pytest --cov=asterix --cov-report=html
# Run specific test
pytest tests/test_agent.py::test_memory_tools
📊 Project Status
Current Version: 0.1.0 (Alpha)
Roadmap:
- Core agent implementation
- Memory tools system
- State persistence
- Qdrant integration
- Enhanced tool registration
- Performance optimizations
- Extended documentation
- Tutorial series
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/your-feature) - Commit your changes (
git commit -m 'Add your feature') - Push to the branch (
git push origin feature/your-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
📞 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Full Docs
So that everyone can build better agents without worrying about memory (Let's hope OpenAI doesn't make this library meaningless)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asterix_agent-0.1.0.tar.gz.
File metadata
- Download URL: asterix_agent-0.1.0.tar.gz
- Upload date:
- Size: 37.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f889154c36065fc0ea1cb9004ca085573353268ebefebf855869f8b59484f6e9
|
|
| MD5 |
ea6a63f9c81e8ed29671b9f571b6c866
|
|
| BLAKE2b-256 |
78702f83207639845afd753bc7ca8a1d215c93eb4df77831c75aacc80de79e57
|
File details
Details for the file asterix_agent-0.1.0-py3-none-any.whl.
File metadata
- Download URL: asterix_agent-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
201fdae862a75cb5dd5edda44dff8aeb0dd64a660fd4c1415abd031c7c66ae9d
|
|
| MD5 |
78732107f12c9df2ee6b7407a20138a3
|
|
| BLAKE2b-256 |
50251537fe09144bac779730a48c12263cb6875ab0673f019c74a79ac62ec623
|