Skip to content

Commit 0a01b8c

Browse files
Merge pull request anthropics#206 from anthropics/zh/add-memory-ctx-mgmt-cookbook
Adds the memory + context management cookbook
2 parents 4b36a1e + 6233c16 commit 0a01b8c

File tree

14 files changed

+2889
-861
lines changed

14 files changed

+2889
-861
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,8 @@ lychee-report.md
149149
# Notebook validation
150150
.notebook_validation_state.json
151151
.notebook_validation_checkpoint.json
152-
validation_report_*.md
152+
validation_report_*.md
153+
# Memory tool demo artifacts
154+
tool_use/demo_memory/
155+
tool_use/memory_storage/
156+
tool_use/.env

tool_use/.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Anthropic API Configuration
2+
# Copy this file to .env and fill in your actual values
3+
4+
# Your Anthropic API key from https://console.anthropic.com/
5+
ANTHROPIC_API_KEY=your_api_key_here
6+
7+
# Model name - Use a model that supports memory_20250818 tool
8+
# Supported models (as of launch):
9+
# - claude-sonnet-4-20250514
10+
# - claude-opus-4-20250514
11+
# - claude-opus-4-1-20250805
12+
# - claude-sonnet-4-5-20250929
13+
14+
ANTHROPIC_MODEL=claude-sonnet-4-5-20250929

tool_use/memory_cookbook.ipynb

Lines changed: 989 additions & 860 deletions
Large diffs are not rendered by default.

tool_use/memory_demo/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignore demo-generated directories and files
2+
demo_memory/
3+
memory_storage/
4+
__pycache__/
5+
*.pyc
Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
"""
2+
Code Review Assistant Demo - Three-session demonstration.
3+
4+
This demo showcases:
5+
1. Session 1: Claude learns debugging patterns
6+
2. Session 2: Claude applies learned patterns (faster!)
7+
3. Session 3: Long session with context editing
8+
9+
Requires:
10+
- .env file with ANTHROPIC_API_KEY and ANTHROPIC_MODEL
11+
- memory_tool.py in the same directory
12+
"""
13+
14+
import os
15+
from typing import Any, Dict, List, Optional
16+
17+
from anthropic import Anthropic
18+
from dotenv import load_dotenv
19+
20+
import sys
21+
from pathlib import Path
22+
23+
# Add parent directory to path to import memory_tool
24+
sys.path.insert(0, str(Path(__file__).parent.parent))
25+
26+
from memory_tool import MemoryToolHandler
27+
28+
29+
# Load environment variables
30+
load_dotenv()
31+
32+
API_KEY = os.getenv("ANTHROPIC_API_KEY")
33+
MODEL = os.getenv("ANTHROPIC_MODEL")
34+
35+
if not API_KEY:
36+
raise ValueError(
37+
"ANTHROPIC_API_KEY not found. Copy .env.example to .env and add your API key."
38+
)
39+
40+
if not MODEL:
41+
raise ValueError(
42+
"ANTHROPIC_MODEL not found. Copy .env.example to .env and set the model."
43+
)
44+
45+
46+
# Context management configuration
47+
CONTEXT_MANAGEMENT = {
48+
"edits": [
49+
{
50+
"type": "clear_tool_uses_20250919",
51+
"trigger": {"type": "input_tokens", "value": 30000},
52+
"keep": {"type": "tool_uses", "value": 3},
53+
"clear_at_least": {"type": "input_tokens", "value": 5000},
54+
}
55+
]
56+
}
57+
58+
59+
class CodeReviewAssistant:
60+
"""
61+
Code review assistant with memory and context editing capabilities.
62+
63+
This assistant:
64+
- Checks memory for debugging patterns before reviewing code
65+
- Stores learned patterns for future sessions
66+
- Automatically clears old tool results when context grows large
67+
"""
68+
69+
def __init__(self, memory_storage_path: str = "./memory_storage"):
70+
"""
71+
Initialize the code review assistant.
72+
73+
Args:
74+
memory_storage_path: Path for memory storage
75+
"""
76+
self.client = Anthropic(api_key=API_KEY)
77+
self.memory_handler = MemoryToolHandler(base_path=memory_storage_path)
78+
self.messages: List[Dict[str, Any]] = []
79+
80+
def _create_system_prompt(self) -> str:
81+
"""Create system prompt with memory instructions."""
82+
return """You are an expert code reviewer focused on finding bugs and suggesting improvements.
83+
84+
MEMORY PROTOCOL:
85+
1. Check your /memories directory for relevant debugging patterns or insights
86+
2. When you find a bug or pattern, update your memory with what you learned
87+
3. Keep your memory organized - use descriptive file names and clear content
88+
89+
When reviewing code:
90+
- Identify bugs, security issues, and code quality problems
91+
- Explain the issue clearly
92+
- Provide a corrected version
93+
- Store important patterns in memory for future reference
94+
95+
Remember: Your memory persists across conversations. Use it wisely."""
96+
97+
def _execute_tool_use(self, tool_use: Any) -> str:
98+
"""Execute a tool use and return the result."""
99+
if tool_use.name == "memory":
100+
result = self.memory_handler.execute(**tool_use.input)
101+
return result.get("success") or result.get("error", "Unknown error")
102+
return f"Unknown tool: {tool_use.name}"
103+
104+
def review_code(
105+
self, code: str, filename: str, description: str = ""
106+
) -> Dict[str, Any]:
107+
"""
108+
Review code with memory-enhanced analysis.
109+
110+
Args:
111+
code: The code to review
112+
filename: Name of the file being reviewed
113+
description: Optional description of what to look for
114+
115+
Returns:
116+
Dict with review results and metadata
117+
"""
118+
# Construct user message
119+
user_message = f"Please review this code from {filename}"
120+
if description:
121+
user_message += f"\n\nContext: {description}"
122+
user_message += f"\n\n```python\n{code}\n```"
123+
124+
self.messages.append({"role": "user", "content": user_message})
125+
126+
# Track token usage and context management
127+
total_input_tokens = 0
128+
context_edits_applied = []
129+
130+
# Conversation loop
131+
turn = 1
132+
while True:
133+
print(f" 🔄 Turn {turn}: Calling Claude API...", end="", flush=True)
134+
response = self.client.beta.messages.create(
135+
model=MODEL,
136+
max_tokens=4096,
137+
system=self._create_system_prompt(),
138+
messages=self.messages,
139+
tools=[{"type": "memory_20250818", "name": "memory"}],
140+
betas=["context-management-2025-06-27"],
141+
extra_body={"context_management": CONTEXT_MANAGEMENT},
142+
)
143+
144+
print(" ✓")
145+
146+
# Track usage
147+
total_input_tokens = response.usage.input_tokens
148+
149+
# Check for context management
150+
if hasattr(response, "context_management") and response.context_management:
151+
applied = response.context_management.get("applied_edits", [])
152+
if applied:
153+
context_edits_applied.extend(applied)
154+
155+
# Process response content
156+
assistant_content = []
157+
tool_results = []
158+
final_text = []
159+
160+
for content in response.content:
161+
if content.type == "text":
162+
assistant_content.append({"type": "text", "text": content.text})
163+
final_text.append(content.text)
164+
elif content.type == "tool_use":
165+
cmd = content.input.get('command', 'unknown')
166+
path = content.input.get('path', '')
167+
print(f" 🔧 Memory: {cmd} {path}")
168+
169+
# Execute tool
170+
result = self._execute_tool_use(content)
171+
172+
assistant_content.append(
173+
{
174+
"type": "tool_use",
175+
"id": content.id,
176+
"name": content.name,
177+
"input": content.input,
178+
}
179+
)
180+
181+
tool_results.append(
182+
{
183+
"type": "tool_result",
184+
"tool_use_id": content.id,
185+
"content": result,
186+
}
187+
)
188+
189+
# Add assistant message
190+
self.messages.append({"role": "assistant", "content": assistant_content})
191+
192+
# If there are tool results, add them and continue
193+
if tool_results:
194+
self.messages.append({"role": "user", "content": tool_results})
195+
turn += 1
196+
else:
197+
# No more tool uses, we're done
198+
print()
199+
break
200+
201+
return {
202+
"review": "\n".join(final_text),
203+
"input_tokens": total_input_tokens,
204+
"context_edits": context_edits_applied,
205+
}
206+
207+
def start_new_session(self) -> None:
208+
"""Start a new conversation session (memory persists)."""
209+
self.messages = []
210+
211+
212+
def run_session_1() -> None:
213+
"""Session 1: Learn debugging patterns."""
214+
print("=" * 80)
215+
print("SESSION 1: Learning from First Code Review")
216+
print("=" * 80)
217+
218+
assistant = CodeReviewAssistant()
219+
220+
# Read sample code
221+
with open("memory_demo/sample_code/web_scraper_v1.py", "r") as f:
222+
code = f.read()
223+
224+
print("\n📋 Reviewing web_scraper_v1.py...")
225+
print("\nMulti-threaded web scraper that sometimes loses results.\n")
226+
227+
result = assistant.review_code(
228+
code=code,
229+
filename="web_scraper_v1.py",
230+
description="This scraper sometimes returns fewer results than expected. "
231+
"The count is inconsistent across runs. Can you find the issue?",
232+
)
233+
234+
print("\n🤖 Claude's Review:\n")
235+
print(result["review"])
236+
print(f"\n📊 Input tokens used: {result['input_tokens']:,}")
237+
238+
if result["context_edits"]:
239+
print(f"\n🧹 Context edits applied: {result['context_edits']}")
240+
241+
print("\n✅ Session 1 complete - Claude learned debugging patterns!\n")
242+
243+
244+
def run_session_2() -> None:
245+
"""Session 2: Apply learned patterns."""
246+
print("=" * 80)
247+
print("SESSION 2: Applying Learned Patterns (New Conversation)")
248+
print("=" * 80)
249+
250+
# New assistant instance (new conversation, but memory persists)
251+
assistant = CodeReviewAssistant()
252+
253+
# Read different sample code with similar bug
254+
with open("memory_demo/sample_code/api_client_v1.py", "r") as f:
255+
code = f.read()
256+
257+
print("\n📋 Reviewing api_client_v1.py...")
258+
print("\nAsync API client with concurrent requests.\n")
259+
260+
result = assistant.review_code(
261+
code=code,
262+
filename="api_client_v1.py",
263+
description="Review this async API client. "
264+
"It fetches multiple endpoints concurrently. Are there any issues?",
265+
)
266+
267+
print("\n🤖 Claude's Review:\n")
268+
print(result["review"])
269+
print(f"\n📊 Input tokens used: {result['input_tokens']:,}")
270+
271+
print("\n✅ Session 2 complete - Claude applied learned patterns faster!\n")
272+
273+
274+
def run_session_3() -> None:
275+
"""Session 3: Long session with context editing."""
276+
print("=" * 80)
277+
print("SESSION 3: Long Session with Context Editing")
278+
print("=" * 80)
279+
280+
assistant = CodeReviewAssistant()
281+
282+
# Read data processor code (has multiple issues)
283+
with open("memory_demo/sample_code/data_processor_v1.py", "r") as f:
284+
code = f.read()
285+
286+
print("\n📋 Reviewing data_processor_v1.py...")
287+
print("\nLarge file with multiple concurrent processing classes.\n")
288+
289+
result = assistant.review_code(
290+
code=code,
291+
filename="data_processor_v1.py",
292+
description="This data processor handles files concurrently. "
293+
"There's also a SharedCache class. Review all components for issues.",
294+
)
295+
296+
print("\n🤖 Claude's Review:\n")
297+
print(result["review"])
298+
print(f"\n📊 Input tokens used: {result['input_tokens']:,}")
299+
300+
if result["context_edits"]:
301+
print("\n🧹 Context Management Applied:")
302+
for edit in result["context_edits"]:
303+
print(f" - Type: {edit.get('type')}")
304+
print(f" - Cleared tool uses: {edit.get('cleared_tool_uses', 0)}")
305+
print(f" - Tokens saved: {edit.get('cleared_input_tokens', 0):,}")
306+
307+
print("\n✅ Session 3 complete - Context editing kept conversation manageable!\n")
308+
309+
310+
def main() -> None:
311+
"""Run all three demo sessions."""
312+
print("\n🚀 Code Review Assistant Demo\n")
313+
print("This demo shows:")
314+
print("1. Session 1: Claude learns debugging patterns")
315+
print("2. Session 2: Claude applies learned patterns (new conversation)")
316+
print("3. Session 3: Long session with context editing\n")
317+
318+
input("Press Enter to start Session 1...")
319+
run_session_1()
320+
321+
input("Press Enter to start Session 2...")
322+
run_session_2()
323+
324+
input("Press Enter to start Session 3...")
325+
run_session_3()
326+
327+
print("=" * 80)
328+
print("🎉 Demo Complete!")
329+
print("=" * 80)
330+
print("\nKey Takeaways:")
331+
print("- Memory tool enabled cross-conversation learning")
332+
print("- Claude got faster at recognizing similar bugs")
333+
print("- Context editing handled long sessions gracefully")
334+
print("\n💡 For production GitHub PR reviews, check out:")
335+
print(" https://github.com/anthropics/claude-code-action\n")
336+
337+
338+
if __name__ == "__main__":
339+
main()

0 commit comments

Comments
 (0)