claude-web/node_modules/@instantlyeasy/claude-code-sdk-ts/examples/fluent-api/new-features/token-streaming.js

214 lines
6.6 KiB
JavaScript
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.

#!/usr/bin/env node
/**
* Token Streaming Example
*
* This example demonstrates how to use the SDK's token streaming feature
* to receive Claude's responses in real-time, token by token.
*
* Use cases:
* - Building responsive chat interfaces
* - Displaying progress for long-running generations
* - Implementing typewriter effects in UIs
*/
import { claude, createTokenStream } from '@instantlyeasy/claude-code-sdk-ts';
async function tokenStreamingExample() {
console.log('📝 Token Streaming Example\n');
// Example 1: Basic token streaming
console.log('1. Basic Token Streaming');
console.log('------------------------');
try {
// Create a raw query generator for token streaming
const messageGenerator = claude()
.withModel('sonnet') // Using faster model for demo
.queryRaw('Write a short story about a robot learning to paint, in exactly 3 sentences.');
// Create a token stream from the message generator
const tokenStream = createTokenStream(messageGenerator);
console.log('Streaming response:\n');
// Collect tokens for display
const tokens = [];
for await (const chunk of tokenStream.tokens()) {
// Display each token as it arrives
process.stdout.write(chunk.token);
tokens.push(chunk.token);
}
// Get streaming metrics
const metrics = tokenStream.getMetrics();
console.log('\n\n📊 Streaming Metrics:');
console.log(`- Tokens received: ${metrics.tokensEmitted}`);
console.log(`- Duration: ${metrics.duration}ms`);
console.log(`- State: ${metrics.state}`);
} catch (error) {
console.error('❌ Streaming error:', error.message);
}
// Example 2: Controlled streaming with pause/resume
console.log('\n\n2. Controlled Streaming (Pause/Resume)');
console.log('--------------------------------------');
try {
const messageGenerator = claude()
.withModel('sonnet')
.queryRaw('Count from 1 to 10 slowly, with each number on a new line.');
const tokenStream = createTokenStream(messageGenerator);
const controller = tokenStream.getController();
console.log('Streaming with pause control:\n');
let tokenCount = 0;
for await (const chunk of tokenStream.tokens()) {
process.stdout.write(chunk.token);
tokenCount++;
// Pause after receiving 5 tokens
if (tokenCount === 5 && controller.getState() === 'streaming') {
console.log('\n\n⏸ Pausing stream for 2 seconds...');
controller.pause();
// Resume after 2 seconds
setTimeout(() => {
console.log('▶️ Resuming stream...\n');
controller.resume();
}, 2000);
}
}
console.log('\n\n✅ Streaming completed');
} catch (error) {
console.error('❌ Controlled streaming error:', error.message);
}
// Example 3: Building a progress indicator
console.log('\n\n3. Progress Indicator Example');
console.log('-----------------------------');
try {
const messageGenerator = claude()
.withModel('sonnet')
.queryRaw('List 5 interesting facts about space exploration.');
const tokenStream = createTokenStream(messageGenerator);
console.log('Generating response with progress:\n');
// Collect tokens while showing progress
const allTokens = [];
const progressWidth = 30;
let receivedTokens = 0;
for await (const chunk of tokenStream.tokens()) {
allTokens.push(chunk.token);
receivedTokens++;
// Update progress bar every 5 tokens
if (receivedTokens % 5 === 0) {
const progress = Math.min(receivedTokens / 100, 1); // Assume ~100 tokens
const filled = Math.floor(progress * progressWidth);
const empty = progressWidth - filled;
process.stdout.write(`\r[${'█'.repeat(filled)}${' '.repeat(empty)}] ${Math.floor(progress * 100)}%`);
}
}
// Clear progress bar and show completion
process.stdout.write('\r' + ' '.repeat(progressWidth + 10) + '\r');
console.log('✅ Response generated successfully!\n');
// Show the complete response
console.log('Complete response:');
console.log(allTokens.join(''));
} catch (error) {
console.error('❌ Progress indicator error:', error.message);
}
// Example 4: Token streaming with event handlers
console.log('\n\n4. Token Streaming with Event Handlers');
console.log('--------------------------------------');
try {
// Track different types of content
let textTokens = 0;
let toolCalls = 0;
const messageGenerator = claude()
.withModel('sonnet')
.onMessage(msg => {
if (msg.type === 'assistant') {
for (const block of msg.content) {
if (block.type === 'tool_use') {
toolCalls++;
}
}
}
})
.queryRaw('What is the weather like today? (Just make something up)');
const tokenStream = createTokenStream(messageGenerator);
console.log('Streaming with event tracking:\n');
for await (const chunk of tokenStream.tokens()) {
process.stdout.write(chunk.token);
textTokens++;
}
console.log('\n\n📊 Event Statistics:');
console.log(`- Text tokens: ${textTokens}`);
console.log(`- Tool calls: ${toolCalls}`);
} catch (error) {
console.error('❌ Event handler error:', error.message);
}
// Example 5: Error handling in token streams
console.log('\n\n5. Token Stream Error Handling');
console.log('------------------------------');
try {
const messageGenerator = claude()
.withModel('sonnet')
.withTimeout(3000) // Short timeout for demo
.queryRaw('Write a very long essay about the history of computing');
const tokenStream = createTokenStream(messageGenerator);
console.log('Attempting to stream with timeout:\n');
try {
for await (const chunk of tokenStream.tokens()) {
process.stdout.write(chunk.token);
}
console.log('\n✅ Completed successfully');
} catch (streamError) {
console.error('\n❌ Stream error:', streamError.message);
const metrics = tokenStream.getMetrics();
console.log('📊 Partial metrics:', {
tokensReceived: metrics.tokensEmitted,
duration: metrics.duration,
state: metrics.state
});
}
} catch (error) {
console.error('❌ Setup error:', error.message);
}
console.log('\n✨ Token streaming examples completed!');
}
// Error handling wrapper
tokenStreamingExample().catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});