-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
144 lines (111 loc) · 3.95 KB
/
Copy pathmain.py
File metadata and controls
144 lines (111 loc) · 3.95 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
#!/usr/bin/env python3
"""
Atomic Stateful Agent - Interactive Console Demo.
This is the main entry point for testing the agent interactively.
It provides a REPL (Read-Eval-Print Loop) for conversing with the agent.
Usage:
python main.py
Commands:
quit, exit - Exit the console
debug - Show current state
reset - Clear all state and start fresh
db - Show MockDB contents
"""
import sys
from pathlib import Path
# Add src to path
sys.path.insert(0, str(Path(__file__).parent))
from src.graph import build_graph, get_graph_state, invoke_graph
from src.mock_db import db
def print_banner():
"""Print the welcome banner."""
print("=" * 60)
print("🤖 Atomic Stateful Agent - Console Demo")
print("=" * 60)
print("Patterns demonstrated:")
print(" • Sticky Router (intent locking)")
print(" • Draft-Commit Protocol (working memory)")
print(" • Recall & Hydrate (edit existing records)")
print("-" * 60)
print("Commands: 'quit', 'debug', 'reset', 'db'")
print("=" * 60)
print()
def print_state(app, thread_id: str):
"""Print the current state in a readable format."""
state = get_graph_state(app, thread_id)
print("\n[DEBUG] Current State:")
print("-" * 40)
print(f" active_intent: {state.get('active_intent')}")
print(f" record_id: {state.get('record_id')}")
draft = state.get('active_draft')
if draft:
print(f" active_draft:")
for key, value in draft.items():
print(f" {key}: {value}")
else:
print(f" active_draft: None")
messages = state.get('messages', [])
print(f" messages: {len(messages)} total")
print("-" * 40)
def print_db():
"""Print MockDB contents."""
print("\n[DB] MockDB Contents:")
print("-" * 40)
tasks = db.list_recent("tasks", limit=10)
if tasks:
for task in tasks:
print(f" [{task['id']}]")
print(f" Title: {task.get('title', 'N/A')}")
print(f" Priority: {task.get('priority', 'normal')}")
print(f" Created: {task.get('created_at', 'N/A')[:19]}")
print()
else:
print(" (empty)")
print("-" * 40)
def main():
"""Run the interactive console."""
print_banner()
# Build the graph with memory
print("Building graph...")
app = build_graph(with_memory=True)
print("Graph ready!\n")
# Session ID for this console session
thread_id = "console-session-001"
while True:
try:
# Get user input
user_input = input("You: ").strip()
if not user_input:
continue
# Handle special commands
if user_input.lower() in ["quit", "exit"]:
print("\n👋 Goodbye!")
break
if user_input.lower() == "debug":
print_state(app, thread_id)
continue
if user_input.lower() == "reset":
thread_id = f"console-session-{__import__('time').time()}"
db.clear()
print("\n🔄 State and DB cleared. New session started.\n")
continue
if user_input.lower() == "db":
print_db()
continue
# Invoke the graph
result = invoke_graph(app, user_input, thread_id)
# Print the response
response = result.get("final_response", "")
if response:
print(f"\nAgent: {response}\n")
else:
print("\nAgent: (no response)\n")
except KeyboardInterrupt:
print("\n\n👋 Interrupted. Goodbye!")
break
except Exception as e:
print(f"\n⚠️ Error: {e}\n")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()