supermemory/packages/tools/test/claude-memory-real-example.ts
rajashidattapy 5db9ceaba2 fix(tools): clear every type error under packages/tools/test
`claude-memory.ts` moved to src/ and five files in test/ kept importing
`./claude-memory`; the Mastra and AI-SDK fixtures drifted behind their
installed types. Together these left `bunx tsc --noEmit` unusable for the
package.

- repoint the five `./claude-memory` imports at `../src/claude-memory`
- add the `state` property Mastra now requires on ProcessInputArgs and
  ProcessOutputResultArgs (35 fixtures)
- add `totalTokens` to the two LanguageModelV2Usage fixtures and drop the
  `rawCall` property the type no longer has
- iterate with `.entries()` instead of indexing, which was tripping
  noUncheckedIndexedAccess once the files started resolving
- pass containerTag/customId through options in test-supermemory.ts, matching
  the current `withSupermemory` signature
- exclude test/chatapp: a standalone Next.js demo with its own package.json,
  lockfile and tsconfig that has no business in this package's program

Repointing the import also made test/claude-memory.test.ts loadable again, and
it turned out to be a live-API suite: gate it behind SUPERMEMORY_API_KEY the
same way the other integration suites are, so `vitest run` no longer collects
a dozen 401s.
2026-10-14 14:43:59 +05:30

360 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Real Claude Memory Tool Integration Examples
*
* This shows actual tool call handling based on real Claude API responses
*/
import {
createClaudeMemoryTool,
type MemoryCommand,
} from "../src/claude-memory"
// =====================================================
// Real Claude API Integration
// =====================================================
/**
* Handle actual Claude memory tool calls from the API response
*/
export async function handleClaudeMemoryToolCall(
toolUseBlock: {
type: "tool_use"
id: string
name: "memory"
input: MemoryCommand
},
supermemoryApiKey: string,
config?: {
namespace?: string
baseUrl?: string
},
) {
console.log(
`🔧 Handling Claude memory tool call: ${toolUseBlock.input.command}`,
)
console.log(`📁 Path: ${toolUseBlock.input.path}`)
// Initialize memory tool
const memoryTool = createClaudeMemoryTool(supermemoryApiKey, {
namespace: config?.namespace || "claude-chat",
baseUrl: config?.baseUrl,
})
// Execute the memory command
const result = await memoryTool.handleCommand(toolUseBlock.input)
// Format response for Claude
const toolResult = {
type: "tool_result" as const,
tool_use_id: toolUseBlock.id,
content: result.success
? result.content || "Operation completed successfully"
: `Error: ${result.error}`,
is_error: !result.success,
}
console.log(
`${result.success ? "✅" : "❌"} Result:`,
result.content || result.error,
)
return toolResult
}
/**
* Complete example with real Claude API call and memory tool handling
*/
export async function realClaudeMemoryExample() {
console.log("🤖 Real Claude Memory Tool Integration")
console.log("=".repeat(50))
// Your API keys
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY
const SUPERMEMORY_API_KEY = process.env.SUPERMEMORY_API_KEY
if (!ANTHROPIC_API_KEY || !SUPERMEMORY_API_KEY) {
console.error("❌ Missing API keys:")
console.error("- Set ANTHROPIC_API_KEY for Claude")
console.error("- Set SUPERMEMORY_API_KEY for Supermemory")
return
}
// Step 1: Make initial request to Claude
console.log("📤 Making request to Claude API...")
const initialRequest = {
model: "claude-sonnet-4-5",
max_tokens: 2048,
messages: [
{
role: "user" as const,
content:
"I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\\n\\n```python\\ndef fetch_page(url, retries=3):\\n for i in range(retries):\\n try:\\n response = requests.get(url, timeout=5)\\n return response.text\\n except requests.exceptions.Timeout:\\n if i == retries - 1:\\n raise\\n time.sleep(1)\\n```\\n\\nPlease help me debug this.",
},
],
tools: [
{
type: "memory_20250818" as const,
name: "memory",
},
],
}
// Make the API call
const claudeResponse = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
"anthropic-beta": "context-management-2025-06-27",
},
body: JSON.stringify(initialRequest),
})
const responseData = await claudeResponse.json()
console.log("📥 Claude's response:")
console.log(JSON.stringify(responseData, null, 2))
// Step 2: Handle any tool calls
const toolResults = []
if (responseData.content) {
const memoryToolCalls = responseData.content.filter(
(
block: any,
): block is {
type: "tool_use"
id: string
name: "memory"
input: { command: MemoryCommand; path: string }
} => block.type === "tool_use" && block.name === "memory",
)
const results = await Promise.all(
memoryToolCalls.map((block: any) => {
console.log("\n🔧 Processing memory tool call:")
console.log(`Command: ${block.input.command}`)
console.log(`Path: ${block.input.path}`)
return handleClaudeMemoryToolCall(block, SUPERMEMORY_API_KEY, {
namespace: "python-scraper-help",
})
}),
)
toolResults.push(...results)
}
// Step 3: Send tool results back to Claude if there were any
if (toolResults.length > 0) {
console.log("\\n📤 Sending tool results back to Claude...")
const followUpRequest = {
model: "claude-sonnet-4-5",
max_tokens: 2048,
messages: [
...initialRequest.messages,
{
role: "assistant" as const,
content: responseData.content,
},
{
role: "user" as const,
content: toolResults,
},
],
tools: initialRequest.tools,
}
const followUpResponse = await fetch(
"https://api.anthropic.com/v1/messages",
{
method: "POST",
headers: {
"x-api-key": ANTHROPIC_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
"anthropic-beta": "context-management-2025-06-27",
},
body: JSON.stringify(followUpRequest),
},
)
const followUpData = await followUpResponse.json()
console.log("📥 Claude's final response:")
console.log(JSON.stringify(followUpData, null, 2))
}
}
/**
* Simplified function to process Claude tool calls
*/
export async function processClaudeResponse(
claudeResponseData: any,
supermemoryApiKey: string,
config?: {
namespace?: string
baseUrl?: string
},
): Promise<any[]> {
const toolResults = []
if (claudeResponseData.content) {
const memoryToolCalls = claudeResponseData.content.filter(
(
block: any,
): block is {
type: "tool_use"
id: string
name: "memory"
input: { command: MemoryCommand; path: string }
} => block.type === "tool_use" && block.name === "memory",
)
const results = await Promise.all(
memoryToolCalls.map((block: any) =>
handleClaudeMemoryToolCall(block, supermemoryApiKey, config),
),
)
toolResults.push(...results)
}
return toolResults
}
// =====================================================
// Express.js / Web Framework Integration Example
// =====================================================
export const webIntegrationExample = `
// Example: Express.js endpoint that handles Claude memory tool calls
import express from 'express';
import { processClaudeResponse } from './claude-memory-real-example';
const app = express();
app.use(express.json());
app.post('/chat-with-memory', async (req, res) => {
const { message, conversationId } = req.body;
try {
// 1. Send message to Claude
const claudeResponse = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
'anthropic-beta': 'context-management-2025-06-27'
},
body: JSON.stringify({
model: 'claude-sonnet-4-5',
max_tokens: 2048,
messages: [{ role: 'user', content: message }],
tools: [{ type: 'memory_20250818', name: 'memory' }]
})
});
const claudeData = await claudeResponse.json();
// 2. Handle any memory tool calls
const toolResults = await processClaudeResponse(
claudeData,
process.env.SUPERMEMORY_API_KEY!,
{
namespace: conversationId || 'default-chat',
}
);
// 3. Send tool results back to Claude if needed
if (toolResults.length > 0) {
const followUpResponse = await fetch('https://api.anthropic.com/v1/messages', {
// ... send tool results back to Claude
});
const finalData = await followUpResponse.json();
res.json({ response: finalData, memoryOperations: toolResults.length });
} else {
res.json({ response: claudeData, memoryOperations: 0 });
}
} catch (error) {
res.status(500).json({ error: 'Failed to process chat with memory' });
}
});
`
// =====================================================
// Test with actual tool call from your example
// =====================================================
export async function testWithRealToolCall() {
console.log("🧪 Testing with Real Tool Call from Your Example")
console.log("=".repeat(50))
// This is the actual tool call Claude made in your example
const realToolCall = {
type: "tool_use" as const,
id: "toolu_01BjWuUZXUfie6ey5Vz3xvth",
name: "memory" as const,
input: {
command: "view" as const,
path: "/memories",
},
}
console.log("🔍 Tool call from Claude:")
console.log(JSON.stringify(realToolCall, null, 2))
if (!process.env.SUPERMEMORY_API_KEY) {
console.error("❌ SUPERMEMORY_API_KEY required for testing")
return
}
// Process the tool call
const result = await handleClaudeMemoryToolCall(
realToolCall,
process.env.SUPERMEMORY_API_KEY,
{
namespace: "python-scraper-debug",
},
)
console.log("\\n📋 Tool Result to send back to Claude:")
console.log(JSON.stringify(result, null, 2))
}
// =====================================================
// Main runner
// =====================================================
export async function runRealExamples() {
console.log("🚀 Running Real Claude Memory Tool Examples")
console.log("=".repeat(70))
// Test with the actual tool call first
await testWithRealToolCall()
console.log(`\\n${"=".repeat(70)}\\n`)
// Show web integration example
console.log("🌐 Web Framework Integration Example:")
console.log(webIntegrationExample)
// Only run full API example if both keys are present
if (process.env.ANTHROPIC_API_KEY && process.env.SUPERMEMORY_API_KEY) {
console.log(`\\n${"=".repeat(70)}\\n`)
await realClaudeMemoryExample()
} else {
console.log(
"\\n⚠️ Set ANTHROPIC_API_KEY and SUPERMEMORY_API_KEY to run full API example",
)
}
}
// Run if executed directly
if (import.meta.main) {
runRealExamples()
}