-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathpostgres_deep_agent.py
More file actions
274 lines (227 loc) · 8.66 KB
/
postgres_deep_agent.py
File metadata and controls
274 lines (227 loc) · 8.66 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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "deepagents==0.5.2",
# "langchain-anthropic==1.4.0",
# "anthropic==0.95.0",
# "deepagents-backends",
# ]
# ///
"""
PostgreSQL Backend Deep Agent Example
This example shows how to create a DeepAgent that stores all its files
in PostgreSQL. This enables:
- ACID-compliant file storage with full transaction support
- Efficient querying with database indexes
- Integration with existing PostgreSQL infrastructure
- Connection pooling for high-performance multi-agent scenarios
Prerequisites:
- PostgreSQL running (docker-compose up -d for local PostgreSQL)
Usage:
uv run examples/postgres_deep_agent.py
"""
import asyncio
import os
import sys
from contextlib import asynccontextmanager
from deepagents import create_deep_agent
from deepagents_backends import PostgresBackend, PostgresConfig
from langchain_anthropic import ChatAnthropic
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
def create_postgres_config_for_local() -> PostgresConfig:
"""Create a PostgreSQL config for local development."""
return PostgresConfig(
host="localhost",
port=5432,
database="deepagents_test",
user="postgres",
password="postgres",
table="agent_files",
min_pool_size=2,
max_pool_size=10,
)
def create_postgres_config_for_production() -> PostgresConfig:
"""Create a PostgreSQL config for production use."""
return PostgresConfig(
host=os.environ.get("POSTGRES_HOST", "postgres.example.com"),
port=int(os.environ.get("POSTGRES_PORT", "5432")),
database=os.environ.get("POSTGRES_DB", "deepagents"),
user=os.environ.get("POSTGRES_USER", "agent_user"),
password=os.environ.get("POSTGRES_PASSWORD", ""),
table="agent_files",
min_pool_size=5,
max_pool_size=20,
sslmode="require", # Always use SSL in production
)
def create_default_model() -> ChatAnthropic:
"""Create a Claude model configured for DeepAgent prompt caching."""
return ChatAnthropic(
model_name="claude-sonnet-4-5-20250929",
max_tokens=20000,
betas=["prompt-caching-2024-07-31"],
)
@asynccontextmanager
async def postgres_backend(config: PostgresConfig):
"""Context manager for PostgresBackend with proper lifecycle management."""
backend = PostgresBackend(config)
try:
# Initialize creates the table and indexes if they don't exist
await backend.initialize()
yield backend
finally:
# Always close the connection pool
await backend.close()
async def main():
"""Run a DeepAgent with PostgreSQL backend for persistent file storage."""
config = create_postgres_config_for_local()
async with postgres_backend(config) as backend:
# Create the deep agent with PostgreSQL backend
# All file operations will use PostgreSQL with connection pooling
agent = create_deep_agent(
model=create_default_model(),
backend=backend,
system_prompt="""You are a data analysis assistant.
When the user asks you to analyze data or create reports:
1. Plan the analysis using todos
2. Create well-documented Python scripts
3. Save results and visualizations to files
4. Generate markdown reports with findings
Files you create will be stored in PostgreSQL and persist across sessions.""",
)
print("Running DeepAgent with PostgreSQL backend...")
print("=" * 60)
result = await agent.ainvoke(
{
"messages": [
{
"role": "user",
"content": """Create a data analysis project structure with:
1. A main analysis script that loads CSV data
2. A utility module for common data operations
3. A README explaining the project
Store all files under /data_analysis/""",
}
]
}
)
# Print the final response
for message in result["messages"]:
if hasattr(message, "content") and message.content:
print(f"\n{message.type}: {message.content[:500]}...")
print("\n" + "=" * 60)
print("Files are now stored in PostgreSQL and will persist!")
async def multi_agent_example():
"""Example: Multiple agents sharing the same PostgreSQL backend.
This demonstrates how PostgreSQL connection pooling enables
efficient multi-agent workflows with shared file access.
"""
config = create_postgres_config_for_local()
async with postgres_backend(config) as backend:
# Create specialized agents that share the same backend
researcher = create_deep_agent(
model=create_default_model(),
backend=backend,
system_prompt="""You are a research agent.
Your job is to research topics and save findings to /research/.""",
)
writer = create_deep_agent(
model=create_default_model(),
backend=backend,
system_prompt="""You are a technical writer.
Read research from /research/ and create polished documentation in /docs/.""",
)
print("Multi-Agent PostgreSQL Example")
print("=" * 60)
# Agent 1: Research phase
print("\n[Researcher Agent] Conducting research...")
await researcher.ainvoke(
{
"messages": [
{
"role": "user",
"content": (
"Research best practices for Python async programming"
" and save notes to /research/async_python.md"
),
}
]
}
)
# Agent 2: Writing phase (reads research agent's output)
print("\n[Writer Agent] Creating documentation...")
await writer.ainvoke(
{
"messages": [
{
"role": "user",
"content": (
"Read the research in /research/ and create a polished"
" guide at /docs/async_guide.md"
),
}
]
}
)
print("\n" + "=" * 60)
print("Multi-agent workflow complete! Both agents shared PostgreSQL storage.")
async def with_subagents_example():
"""Example: Using sub-agents with PostgreSQL backend."""
config = create_postgres_config_for_local()
async with postgres_backend(config) as backend:
# Define specialized sub-agents
code_reviewer = {
"name": "code-reviewer",
"description": "Reviews code for quality and suggests improvements",
"system_prompt": """You are an expert code reviewer.
Analyze code files and provide detailed feedback on:
- Code quality and readability
- Potential bugs or issues
- Performance considerations
- Best practices""",
}
test_writer = {
"name": "test-writer",
"description": "Creates comprehensive test suites",
"system_prompt": """You are a testing expert.
Create thorough test suites with:
- Unit tests for all functions
- Edge case coverage
- Clear test documentation""",
}
# Main agent can delegate to sub-agents
agent = create_deep_agent(
model=create_default_model(),
backend=backend,
subagents=[code_reviewer, test_writer],
system_prompt="""You are a senior developer who coordinates code quality.
For code quality tasks:
1. Use the code-reviewer sub-agent to analyze existing code
2. Use the test-writer sub-agent to create tests
3. Synthesize feedback and create improvement plans
All files are stored in PostgreSQL for persistence.""",
)
print("Sub-agents with PostgreSQL Example")
print("=" * 60)
await agent.ainvoke(
{
"messages": [
{
"role": "user",
"content": """Review the code in /data_analysis/ (if it exists) and:
1. Delegate to code-reviewer for quality analysis
2. Delegate to test-writer to create tests
3. Summarize findings in /reviews/analysis_review.md""",
}
]
}
)
print("Sub-agent workflow complete!")
if __name__ == "__main__":
# Run the primary example
asyncio.run(main())
# Optional advanced demos (uncomment one at a time):
# asyncio.run(multi_agent_example())
# asyncio.run(with_subagents_example())