Skip to content

Commit 8a3d650

Browse files
implemented intermediate starter with planning and memory hardcoded behavior
1 parent 6ff15e6 commit 8a3d650

8 files changed

Lines changed: 1308 additions & 281 deletions

File tree

python/evals/eval_agent.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ def format_observation_summary(obs) -> str:
184184

185185
def run_scenario(agent, name: str, scenario: dict, index: int, total: int) -> dict:
186186
"""Run a single scenario and display the result."""
187+
# Reset stateful agents between scenarios so memory doesn't bleed across
188+
if hasattr(agent, "memory") and hasattr(agent.memory, "clear"):
189+
agent.memory.clear()
190+
if hasattr(agent, "planner") and hasattr(agent.planner, "cancel"):
191+
agent.planner.cancel()
192+
if hasattr(agent, "visited_positions"):
193+
agent.visited_positions.clear()
194+
187195
obs = scenario["observation"]
188196
print(f"\n[{index}/{total}] {name}")
189197
print(f" {scenario['description']}")

starters/intermediate/README.md

Lines changed: 160 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
# Intermediate Agent Starter
22

3-
Agent with memory and planning for more sophisticated strategies.
3+
Agent with memory, multi-step planning, and crafting for more sophisticated strategies.
44

5-
## What's New vs Beginner
5+
## What's Different vs Beginner
66

77
| Feature | Beginner | Intermediate |
88
|---------|----------|--------------|
9-
| Memory | None | Last 50 observations |
10-
| Planning | React only | Goal decomposition |
11-
| Exploration | Random | Avoids revisiting |
12-
| Decision making | Immediate | Considers history |
9+
| Memory | None — each tick is fresh | Last 50 observations |
10+
| Planning | React to what's visible | Multi-step plans across ticks |
11+
| Resource finding | Only visible resources | Visible + remembered locations |
12+
| Hazard avoidance | Only visible hazards | Visible + remembered hazard zones |
13+
| Crafting | Only when already at station | Plans: gather materials → go to station → craft |
14+
| Exploration | First frontier target | Avoids revisiting, seeks productive areas |
15+
| Tool results | Ignored | Detects failures and replans |
16+
| Pattern detection | None | Finds resource clusters |
1317

1418
## Files
1519

1620
```
1721
intermediate/
18-
├── agent.py # Agent with memory & planning
19-
├── memory.py # Sliding window memory (YOUR CODE!)
20-
├── planner.py # Goal decomposition (YOUR CODE!)
21-
├── run.py # Entry point
22+
├── agent.py # Decision logic with memory + planning
23+
├── memory.py # Sliding window memory with pattern detection (YOUR CODE!)
24+
├── planner.py # Goal decomposition + multi-step plans (YOUR CODE!)
25+
├── run.py # Entry point — connects to Agent Arena
26+
├── test_agent.py # Unit tests (run with pytest)
2227
└── requirements.txt # Just the SDK
2328
```
2429

@@ -31,66 +36,171 @@ python run.py
3136

3237
Then connect from Agent Arena game.
3338

34-
## How Memory Works
39+
## How It Works
40+
41+
```
42+
Observation ──► Memory ──► Planner ──► Agent ──► Decision
43+
│ │ │
44+
│ decompose into │
45+
│ sub-goals execute plan
46+
│ │ step-by-step
47+
│ ▼ │
48+
│ ActionStep[] │
49+
│ [move_to, │
50+
│ collect, │
51+
│ craft_item] │
52+
│ │ │
53+
▼ ▼ ▼
54+
find_uncollected plan_collect Decision(tool, params)
55+
find_hazard_zones plan_craft
56+
find_productive plan_explore
57+
```
58+
59+
### Decision Priority
60+
61+
Each tick, the agent decides in this order:
62+
63+
1. **Handle tool result** — Did the last action succeed? Advance the plan or replan.
64+
2. **Escape danger** — Nearby hazard? Cancel plan and flee.
65+
3. **Continue plan** — Mid-plan? Execute the next step.
66+
4. **Pursue objectives** — No plan? Decompose objective into sub-goals, create a plan.
67+
5. **Opportunistic craft** — At a station with materials? Craft something.
68+
6. **Explore** — Nothing to do? Head toward productive areas or frontiers.
69+
70+
### Multi-Step Plans
71+
72+
Instead of choosing one action per tick, the planner creates a **sequence of steps** and executes them across ticks:
3573

3674
```python
37-
from memory import SlidingWindowMemory
75+
# Example: Crafting a torch
76+
planner.plan_craft("torch", "workbench_001", station_pos,
77+
missing_materials=[("wood_001", wood_pos)])
78+
# Creates: [move_to wood, collect wood, move_to workbench, craft torch]
79+
```
3880

39-
memory = SlidingWindowMemory(capacity=50)
81+
If any step fails (tool result reports error), the plan is cancelled and the agent replans.
4082

41-
# Store each observation
42-
memory.store(obs)
83+
### Memory-Driven Decisions
84+
85+
The agent doesn't just react to what's visible — it remembers:
86+
87+
```python
88+
# "I saw a berry at (10, 0, 5) on tick 3. Nothing visible now, so go back."
89+
uncollected = memory.find_uncollected_resources(current_tick)
4390

44-
# Retrieve recent history
45-
last_10 = memory.get_recent(10)
91+
# "Fire was at (5, 0, 5) recently. Stay away."
92+
hazard_zones = memory.find_hazard_zones(current_tick)
4693

47-
# Find things you've seen
48-
resources = memory.find_resources_seen()
49-
hazards = memory.find_hazards_seen()
94+
# "Resources tend to cluster near (12, 0, 8). Explore there."
95+
productive = memory.find_productive_areas()
5096
```
5197

52-
## How Planning Works
98+
## Modification Ideas
99+
100+
### 1. Change Hazard Avoidance Radius (Simple)
101+
102+
In `agent.py`, the agent flees when a hazard is within 3 units and avoids
103+
remembered hazards within 4 units. Try adjusting:
53104

54105
```python
55-
from planner import Planner
106+
# In _check_danger():
107+
if hazard.distance < 5.0: # Was 3.0 — more cautious
108+
...
109+
if distance < 6.0: # Was 4.0 — wider remembered-hazard buffer
110+
...
111+
```
112+
113+
### 2. Add a New Recipe (Intermediate)
114+
115+
Add a recipe to `agent.py` and the agent will automatically plan for it:
56116

57-
planner = Planner()
117+
```python
118+
RECIPES = {
119+
"torch": ("workbench", {"wood": 1, "stone": 1}),
120+
"meal": ("workbench", {"berry": 2}),
121+
"shelter": ("anvil", {"wood": 3, "stone": 2}),
122+
"potion": ("workbench", {"berry": 1, "mushroom": 1}), # NEW
123+
}
124+
```
58125

59-
# Break objective into sub-goals
60-
sub_goals = planner.decompose(obs.objective, obs.current_progress)
126+
### 3. Implement Resource Value Weighting (Advanced)
61127

62-
# Pick highest priority
63-
current_goal = planner.select_goal(sub_goals)
128+
Instead of always picking the closest resource, weight by type value:
64129

65-
# Work on it
66-
decision = execute_sub_goal(current_goal, obs)
130+
```python
131+
# In _plan_resource_collection():
132+
RESOURCE_VALUES = {"gold": 10, "stone": 3, "wood": 2, "berry": 1}
133+
134+
if obs.nearby_resources:
135+
# Score = value / distance (higher is better)
136+
best = max(
137+
obs.nearby_resources,
138+
key=lambda r: RESOURCE_VALUES.get(r.type, 1) / max(r.distance, 0.1),
139+
)
67140
```
68141

69-
## Modification Ideas
142+
### 4. Add Exploration Memory Decay (Advanced)
143+
144+
Make the agent forget old productive areas and re-explore:
145+
146+
```python
147+
# In memory.py, modify find_productive_areas():
148+
# Only count resources seen in the last 30 ticks
149+
resource_positions = []
150+
for obs in self._observations:
151+
if current_tick - obs.tick < 30: # Recency window
152+
for resource in obs.nearby_resources:
153+
resource_positions.append(resource.position)
154+
```
70155

71-
**Memory enhancements:**
72-
- Semantic search
73-
- Importance weighting
74-
- Compression/summarization
156+
## Debugging Tips
75157

76-
**Planning improvements:**
77-
- Multi-step plans
78-
- Dependency tracking
79-
- Dynamic re-planning
158+
### Inspect Memory State
80159

81-
**State tracking:**
82-
- World model
83-
- Resource timers
84-
- Hazard predictions
160+
Add a print in `decide()` to see what the agent remembers:
85161

86-
## When to Graduate
162+
```python
163+
def decide(self, obs):
164+
self.memory.store(obs)
165+
print(self.memory.summarize()) # Shows resources, hazards, productive areas
166+
...
167+
```
87168

88-
Move to `llm/` starter when you want:
89-
- Natural language reasoning
90-
- Complex decision making
91-
- Few-shot learning from examples
169+
### Trace Planning Decisions
170+
171+
See what the planner is doing:
172+
173+
```python
174+
sub_goals = self.planner.decompose(obs.objective, obs.current_progress)
175+
print(self.planner.explain_plan(sub_goals))
176+
```
177+
178+
### Run Eval Scenarios
179+
180+
Test specific situations without running the full game:
92181

93-
## Resources
182+
```bash
183+
# Run all scenarios
184+
python ../../python/evals/eval_agent.py --adapter intermediate
185+
186+
# Test just hazard escape
187+
python ../../python/evals/eval_agent.py --adapter intermediate --scenario hazard_escape
188+
189+
# Interactive mode — type your own observations
190+
python ../../python/evals/eval_agent.py --adapter intermediate --interactive
191+
```
192+
193+
### Run Unit Tests
194+
195+
```bash
196+
python -m pytest test_agent.py -v
197+
```
198+
199+
## When to Graduate
200+
201+
Move to the `claude/` or `langgraph/` starter when you want:
94202

95-
- [Memory Systems](../../docs/memory_systems.md)
96-
- [Planning Strategies](../../docs/planning.md)
203+
- Natural language reasoning about complex situations
204+
- LLM-driven tool selection instead of if/else logic
205+
- Framework observability (LangSmith, Anthropic Console)
206+
- Few-shot learning from examples

0 commit comments

Comments
 (0)