Skip to content

Commit 6b1ed21

Browse files
committed
example for planner + executor agent
1 parent f1fb05e commit 6b1ed21

File tree

2 files changed

+426
-0
lines changed

2 files changed

+426
-0
lines changed
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#!/usr/bin/env python3
2+
"""
3+
PlannerExecutorAgent example with custom configuration.
4+
5+
This example demonstrates various configuration options:
6+
- Snapshot escalation (enable/disable, custom step sizes)
7+
- Retry configuration (timeouts, max attempts)
8+
- Vision fallback settings
9+
10+
Usage:
11+
export OPENAI_API_KEY="sk-..."
12+
python custom_config_example.py
13+
"""
14+
15+
from __future__ import annotations
16+
17+
import asyncio
18+
import os
19+
20+
from predicate import AsyncPredicateBrowser
21+
from predicate.agent_runtime import AgentRuntime
22+
from predicate.agents import (
23+
PlannerExecutorAgent,
24+
PlannerExecutorConfig,
25+
RetryConfig,
26+
SnapshotEscalationConfig,
27+
)
28+
from predicate.agents.browser_agent import VisionFallbackConfig
29+
from predicate.backends.playwright_backend import PlaywrightBackend
30+
from predicate.llm_provider import OpenAIProvider
31+
32+
33+
async def example_default_config() -> None:
34+
"""Default configuration: escalation enabled, step=30."""
35+
print("\n--- Example 1: Default Config ---")
36+
print("Escalation: 60 -> 90 -> 120 -> 150 -> 180 -> 200")
37+
38+
config = PlannerExecutorConfig()
39+
40+
print(f" snapshot.enabled: {config.snapshot.enabled}")
41+
print(f" snapshot.limit_base: {config.snapshot.limit_base}")
42+
print(f" snapshot.limit_step: {config.snapshot.limit_step}")
43+
print(f" snapshot.limit_max: {config.snapshot.limit_max}")
44+
45+
46+
async def example_disabled_escalation() -> None:
47+
"""Disable escalation: always use limit_base."""
48+
print("\n--- Example 2: Disabled Escalation ---")
49+
print("Escalation: disabled (always 60)")
50+
51+
config = PlannerExecutorConfig(
52+
snapshot=SnapshotEscalationConfig(enabled=False),
53+
)
54+
55+
print(f" snapshot.enabled: {config.snapshot.enabled}")
56+
print(f" snapshot.limit_base: {config.snapshot.limit_base}")
57+
58+
59+
async def example_custom_step_size() -> None:
60+
"""Custom step size for faster escalation."""
61+
print("\n--- Example 3: Custom Step Size ---")
62+
print("Escalation: 60 -> 110 -> 160 -> 200 (step=50)")
63+
64+
config = PlannerExecutorConfig(
65+
snapshot=SnapshotEscalationConfig(
66+
limit_step=50, # Larger steps = fewer iterations
67+
),
68+
)
69+
70+
print(f" snapshot.limit_step: {config.snapshot.limit_step}")
71+
72+
73+
async def example_custom_limits() -> None:
74+
"""Custom base and max limits."""
75+
print("\n--- Example 4: Custom Limits ---")
76+
print("Escalation: 100 -> 125 -> 150 -> 175 -> 200 -> 225 -> 250")
77+
78+
config = PlannerExecutorConfig(
79+
snapshot=SnapshotEscalationConfig(
80+
limit_base=100, # Start higher
81+
limit_step=25, # Smaller increments
82+
limit_max=250, # Higher maximum
83+
),
84+
)
85+
86+
print(f" snapshot.limit_base: {config.snapshot.limit_base}")
87+
print(f" snapshot.limit_step: {config.snapshot.limit_step}")
88+
print(f" snapshot.limit_max: {config.snapshot.limit_max}")
89+
90+
91+
async def example_retry_config() -> None:
92+
"""Custom retry configuration."""
93+
print("\n--- Example 5: Retry Config ---")
94+
95+
config = PlannerExecutorConfig(
96+
retry=RetryConfig(
97+
verify_timeout_s=15.0, # Longer timeout for slow pages
98+
verify_poll_s=0.3, # Faster polling
99+
verify_max_attempts=10, # More verification attempts
100+
executor_repair_attempts=3, # More repair attempts
101+
max_replans=2, # Allow 2 replans on failure
102+
),
103+
)
104+
105+
print(f" retry.verify_timeout_s: {config.retry.verify_timeout_s}")
106+
print(f" retry.verify_max_attempts: {config.retry.verify_max_attempts}")
107+
print(f" retry.max_replans: {config.retry.max_replans}")
108+
109+
110+
async def example_vision_fallback() -> None:
111+
"""Vision fallback configuration."""
112+
print("\n--- Example 6: Vision Fallback ---")
113+
114+
config = PlannerExecutorConfig(
115+
vision=VisionFallbackConfig(
116+
enabled=True,
117+
max_vision_calls=5, # Up to 5 vision calls per run
118+
trigger_requires_vision=True, # Trigger on require_vision status
119+
trigger_canvas_or_low_actionables=True, # Trigger on canvas pages
120+
),
121+
)
122+
123+
print(f" vision.enabled: {config.vision.enabled}")
124+
print(f" vision.max_vision_calls: {config.vision.max_vision_calls}")
125+
126+
127+
async def example_full_custom() -> None:
128+
"""Full custom configuration with all options."""
129+
print("\n--- Example 7: Full Custom Config ---")
130+
131+
config = PlannerExecutorConfig(
132+
# Snapshot escalation
133+
snapshot=SnapshotEscalationConfig(
134+
enabled=True,
135+
limit_base=80,
136+
limit_step=40,
137+
limit_max=240,
138+
),
139+
# Retry settings
140+
retry=RetryConfig(
141+
verify_timeout_s=12.0,
142+
verify_poll_s=0.4,
143+
verify_max_attempts=6,
144+
max_replans=2,
145+
),
146+
# Vision fallback
147+
vision=VisionFallbackConfig(
148+
enabled=True,
149+
max_vision_calls=3,
150+
),
151+
# Planner settings
152+
planner_max_tokens=3000,
153+
planner_temperature=0.0,
154+
# Executor settings
155+
executor_max_tokens=128,
156+
executor_temperature=0.0,
157+
# Tracing
158+
trace_screenshots=True,
159+
trace_screenshot_format="jpeg",
160+
trace_screenshot_quality=85,
161+
)
162+
163+
print(" Full config created successfully!")
164+
print(f" Escalation: {config.snapshot.limit_base} -> ... -> {config.snapshot.limit_max}")
165+
print(f" Max replans: {config.retry.max_replans}")
166+
print(f" Vision enabled: {config.vision.enabled}")
167+
168+
169+
async def example_run_with_config() -> None:
170+
"""Run agent with custom config."""
171+
print("\n--- Example 8: Run Agent with Custom Config ---")
172+
173+
openai_key = os.getenv("OPENAI_API_KEY")
174+
if not openai_key:
175+
print(" Skipping (no OPENAI_API_KEY)")
176+
return
177+
178+
predicate_api_key = os.getenv("PREDICATE_API_KEY")
179+
180+
# Create config optimized for reliability
181+
config = PlannerExecutorConfig(
182+
snapshot=SnapshotEscalationConfig(
183+
enabled=True,
184+
limit_base=60,
185+
limit_step=30,
186+
limit_max=180,
187+
),
188+
retry=RetryConfig(
189+
verify_timeout_s=10.0,
190+
max_replans=1,
191+
),
192+
)
193+
194+
planner = OpenAIProvider(model="gpt-4o")
195+
executor = OpenAIProvider(model="gpt-4o-mini")
196+
197+
agent = PlannerExecutorAgent(
198+
planner=planner,
199+
executor=executor,
200+
config=config,
201+
)
202+
203+
async with AsyncPredicateBrowser(
204+
api_key=predicate_api_key,
205+
headless=True,
206+
) as browser:
207+
page = await browser.new_page()
208+
await page.goto("https://example.com")
209+
210+
backend = PlaywrightBackend(page)
211+
runtime = AgentRuntime(backend=backend)
212+
213+
result = await agent.run(
214+
runtime=runtime,
215+
task="Verify example.com is loaded",
216+
)
217+
218+
print(f" Success: {result.success}")
219+
print(f" Steps: {result.steps_completed}/{result.steps_total}")
220+
221+
222+
async def main() -> None:
223+
print("PlannerExecutorAgent Configuration Examples")
224+
print("=" * 50)
225+
226+
await example_default_config()
227+
await example_disabled_escalation()
228+
await example_custom_step_size()
229+
await example_custom_limits()
230+
await example_retry_config()
231+
await example_vision_fallback()
232+
await example_full_custom()
233+
await example_run_with_config()
234+
235+
print("\n" + "=" * 50)
236+
print("Done!")
237+
238+
239+
if __name__ == "__main__":
240+
asyncio.run(main())

0 commit comments

Comments
 (0)