195 lines
4.7 KiB
TypeScript
195 lines
4.7 KiB
TypeScript
import Anthropic from '@anthropic-ai/sdk';
|
|
|
|
const anthropic = new Anthropic({
|
|
apiKey: process.env.ANTHROPIC_API_KEY || '',
|
|
});
|
|
|
|
// Method 1: Using SDK stream helper with event listeners
|
|
async function streamWithEvents() {
|
|
console.log('Claude:');
|
|
|
|
const stream = anthropic.messages.stream({
|
|
model: 'claude-sonnet-4-5-20250929',
|
|
max_tokens: 1024,
|
|
messages: [
|
|
{
|
|
role: 'user',
|
|
content: 'Write a short poem about coding.',
|
|
},
|
|
],
|
|
});
|
|
|
|
stream
|
|
.on('text', (text) => {
|
|
process.stdout.write(text);
|
|
})
|
|
.on('message', (message) => {
|
|
console.log('\n\nFinal message:', message);
|
|
console.log('Stop reason:', message.stop_reason);
|
|
})
|
|
.on('error', (error) => {
|
|
console.error('\nStream error:', error);
|
|
})
|
|
.on('abort', (error) => {
|
|
console.warn('\nStream aborted:', error);
|
|
})
|
|
.on('end', () => {
|
|
console.log('\n\nStream ended');
|
|
});
|
|
|
|
// Wait for stream to complete
|
|
const finalMessage = await stream.finalMessage();
|
|
return finalMessage;
|
|
}
|
|
|
|
// Method 2: Manual iteration over stream events
|
|
async function streamWithManualIteration() {
|
|
console.log('Claude:');
|
|
|
|
const stream = await anthropic.messages.create({
|
|
model: 'claude-sonnet-4-5-20250929',
|
|
max_tokens: 1024,
|
|
messages: [
|
|
{
|
|
role: 'user',
|
|
content: 'Explain quantum computing in simple terms.',
|
|
},
|
|
],
|
|
stream: true,
|
|
});
|
|
|
|
let fullText = '';
|
|
|
|
try {
|
|
for await (const event of stream) {
|
|
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
|
|
const text = event.delta.text;
|
|
fullText += text;
|
|
process.stdout.write(text);
|
|
}
|
|
|
|
if (event.type === 'message_stop') {
|
|
console.log('\n\nStream complete');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('\nStream error:', error);
|
|
throw error;
|
|
}
|
|
|
|
return fullText;
|
|
}
|
|
|
|
// Method 3: Streaming with abort control
|
|
async function streamWithAbort() {
|
|
console.log('Claude (can be aborted):');
|
|
|
|
const stream = anthropic.messages.stream({
|
|
model: 'claude-sonnet-4-5-20250929',
|
|
max_tokens: 2048,
|
|
messages: [
|
|
{
|
|
role: 'user',
|
|
content: 'Write a long essay about the history of computers.',
|
|
},
|
|
],
|
|
});
|
|
|
|
let charCount = 0;
|
|
const maxChars = 200; // Abort after 200 characters
|
|
|
|
stream.on('text', (text) => {
|
|
process.stdout.write(text);
|
|
charCount += text.length;
|
|
|
|
// Abort stream after reaching limit
|
|
if (charCount >= maxChars) {
|
|
console.log('\n\n[Aborting stream after', charCount, 'characters]');
|
|
stream.abort();
|
|
}
|
|
});
|
|
|
|
stream.on('abort', () => {
|
|
console.log('Stream was aborted successfully');
|
|
});
|
|
|
|
stream.on('error', (error) => {
|
|
console.error('Stream error:', error);
|
|
});
|
|
|
|
try {
|
|
await stream.done();
|
|
} catch (error) {
|
|
// Handle abort error
|
|
if (error.name === 'APIUserAbortError') {
|
|
console.log('Stream aborted by user');
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Method 4: Streaming with retry logic
|
|
async function streamWithRetry(maxRetries = 3) {
|
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
try {
|
|
const stream = anthropic.messages.stream({
|
|
model: 'claude-sonnet-4-5-20250929',
|
|
max_tokens: 1024,
|
|
messages: [
|
|
{
|
|
role: 'user',
|
|
content: 'Tell me a fun fact about space.',
|
|
},
|
|
],
|
|
});
|
|
|
|
let fullText = '';
|
|
|
|
stream.on('text', (text) => {
|
|
fullText += text;
|
|
process.stdout.write(text);
|
|
});
|
|
|
|
stream.on('error', (error) => {
|
|
console.error(`\nStream error on attempt ${attempt + 1}:`, error);
|
|
throw error;
|
|
});
|
|
|
|
await stream.finalMessage();
|
|
console.log('\n\nStream completed successfully');
|
|
return fullText;
|
|
} catch (error) {
|
|
if (attempt < maxRetries - 1) {
|
|
const delay = Math.pow(2, attempt) * 1000;
|
|
console.log(`\nRetrying in ${delay}ms...`);
|
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
} else {
|
|
console.error('\nMax retries exceeded');
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run examples
|
|
if (require.main === module) {
|
|
console.log('=== Stream with Events ===\n');
|
|
streamWithEvents()
|
|
.then(() => {
|
|
console.log('\n\n=== Stream with Manual Iteration ===\n');
|
|
return streamWithManualIteration();
|
|
})
|
|
.then(() => {
|
|
console.log('\n\n=== Stream with Abort ===\n');
|
|
return streamWithAbort();
|
|
})
|
|
.then(() => {
|
|
console.log('\n\n=== Stream with Retry ===\n');
|
|
return streamWithRetry();
|
|
})
|
|
.catch(console.error);
|
|
}
|
|
|
|
export { streamWithEvents, streamWithManualIteration, streamWithAbort, streamWithRetry };
|