-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathsimple_agent.py
More file actions
197 lines (155 loc) · 6.1 KB
/
simple_agent.py
File metadata and controls
197 lines (155 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env python
"""
Simple HMLR + LangGraph Example
This example shows how to add HMLR long-term memory to a basic agent.
Prerequisites:
pip install langgraph langchain-core langchain-openai
Usage:
python simple_agent.py
"""
import asyncio
import os
from typing import Annotated
from pathlib import Path
# Load .env file
from dotenv import load_dotenv
env_path = Path(__file__).parent.parent.parent.parent / ".env"
load_dotenv(env_path)
# Check for LangGraph
try:
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
except ImportError:
print("Please install langgraph: pip install langgraph langchain-core")
exit(1)
# Check for LangChain OpenAI
try:
from langchain_openai import ChatOpenAI
except ImportError:
print("Please install langchain-openai: pip install langchain-openai")
exit(1)
# Import HMLR integration
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
from hmlr.integrations.langgraph.nodes import hmlr_memory_node
from hmlr.integrations.langgraph.state import HMLRState
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("=" * 60)
print("ERROR: OPENAI_API_KEY environment variable not set!")
print("=" * 60)
print("\nSet it with PowerShell:")
print(' $env:OPENAI_API_KEY = "your-key-here"')
print("\nOr set it permanently in Windows environment variables.")
exit(1)
# Create LLM
llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0.7)
async def llm_node(state: HMLRState) -> dict:
"""
LLM node that uses HMLR context.
The hmlr_memory_node has already populated:
- state["hmlr_context"]: Formatted context string
- state["user_profile"]: User constraints/preferences
"""
messages = state.get("messages", [])
hmlr_context = state.get("hmlr_context")
# Build system message with HMLR context
system_parts = ["You are a helpful assistant with long-term memory."]
if hmlr_context:
system_parts.append(
f"\nHere is relevant context from previous conversations:\n{hmlr_context}"
)
system_parts.append(
"\nUse this context to provide personalized, consistent responses. "
"Remember user preferences and past discussions."
)
system_message = {"role": "system", "content": "\n".join(system_parts)}
# Call LLM
full_messages = [system_message] + messages
response = await llm.ainvoke(full_messages)
return {
"messages": [{"role": "assistant", "content": response.content}]
}
def build_agent(use_hmlr_llm: bool = True):
"""
Build the LangGraph agent with HMLR memory.
Args:
use_hmlr_llm: If True, use HMLR's full chat (includes persistence + Scribe).
If False, use separate memory retrieval + custom LLM.
"""
from hmlr.integrations.langgraph.nodes import hmlr_chat_node
graph = StateGraph(HMLRState)
if use_hmlr_llm:
# OPTION A: HMLR handles everything (recommended for persistence)
# This includes: retrieval, LLM call, conversation persistence, Scribe
graph.add_node("chat", hmlr_chat_node)
graph.set_entry_point("chat")
graph.add_edge("chat", END)
else:
# OPTION B: HMLR retrieval + custom LLM (no persistence)
graph.add_node("memory", hmlr_memory_node)
graph.add_node("llm", llm_node)
graph.set_entry_point("memory")
graph.add_edge("memory", "llm")
graph.add_edge("llm", END)
return graph.compile()
async def main():
"""Run the agent interactively."""
print("=" * 60)
print("HMLR + LangGraph Simple Agent")
print("=" * 60)
# Pre-warm HMLR (loads embedding models, ~3-5 seconds)
print("Initializing HMLR memory system...")
from hmlr.integrations.langgraph.client import get_client_manager
manager = get_client_manager()
engine = manager.get_engine({}, raise_on_error=False)
if engine is None:
print("⚠️ WARNING: HMLR engine failed to initialize. Memory disabled.")
else:
print("✓ HMLR ready")
print("\nThis agent has long-term memory powered by HMLR.")
print("Try telling it something about yourself, then asking about it later!")
print("Type 'quit' to exit.\n")
agent = build_agent()
session_id = "demo-session"
messages = []
while True:
try:
user_input = input("You: ").strip()
if user_input.lower() in ("quit", "exit", "q"):
print("Goodbye!")
break
if not user_input:
continue
# Add user message
messages.append({"role": "user", "content": user_input})
# Run agent
result = await agent.ainvoke(
{"messages": messages, "session_id": session_id},
config={"configurable": {"thread_id": session_id}}
)
# Get response
response_messages = result.get("messages", [])
if response_messages:
last_msg = response_messages[-1]
# Handle both dict and LangChain message objects
if isinstance(last_msg, dict):
content = last_msg.get("content", str(last_msg))
elif hasattr(last_msg, "content"):
content = last_msg.content
else:
content = str(last_msg)
print(f"\nAssistant: {content}\n")
# Update messages for next turn (convert to list if needed)
messages = list(response_messages)
# Show HMLR stats
contexts = result.get("contexts_retrieved", 0)
if contexts > 0:
print(f"[HMLR: Retrieved {contexts} relevant memories]")
except KeyboardInterrupt:
print("\nGoodbye!")
break
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
asyncio.run(main())