
Melodic speech for LLMs
Enterprise-ready multi-provider LLM chat SDK with a unified interface for OpenAI, Anthropic, Google, and Ollama (local models).
AsyncIteratorStage 6 - Future Enhancements
npm install meloqui
import { ChatClient } from 'meloqui';
// Create a client (API key from OPENAI_API_KEY env variable)
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4'
});
// Send a message
const response = await client.chat('Hello! What is TypeScript?', {
temperature: 0.7,
maxTokens: 150
});
console.log(response.content);
// Output: TypeScript is a strongly typed programming language...
import { ChatClient } from 'meloqui';
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4'
});
// Stream responses in real-time
for await (const chunk of client.stream('Tell me a story')) {
process.stdout.write(chunk.content);
}
import { ChatClient } from 'meloqui';
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
conversationId: 'user-123' // Enable automatic history tracking
});
await client.chat('My name is Alice');
await client.chat('What is my name?'); // Remembers context
// Retrieve full history
const history = await client.getHistory();
console.log(history); // [{ role: 'user', content: 'My name is Alice' }, ...]
import { ChatClient, FileStorage } from 'meloqui';
const storage = new FileStorage('./conversations');
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
conversationId: 'user-123',
storage // Conversations persist across sessions
});
await client.chat('Remember: my favorite color is blue');
// Later, in a new session...
const newClient = new ChatClient({
provider: 'openai',
model: 'gpt-4',
conversationId: 'user-123',
storage // Loads previous conversation
});
await newClient.chat('What is my favorite color?'); // Remembers!
Run models locally with Ollama for privacy and offline use.
import { ChatClient } from 'meloqui';
// Use Ollama with local models (no API key needed)
const client = new ChatClient({
provider: 'ollama',
model: 'llama3.2' // or mistral, codellama, phi, etc.
});
const response = await client.chat('Explain quantum computing');
console.log(response.content);
Remote Ollama Server:
const client = new ChatClient({
provider: 'ollama',
model: 'llama3.2',
baseUrl: 'http://my-server:11434'
});
Requirements: Ollama must be running locally (default:
http://localhost:11434) or accessible via network. Install withbrew install ollama(macOS) or see ollama.ai for other platforms.
Automatic retry with exponential backoff for resilience against transient failures.
import { ChatClient } from 'meloqui';
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
retryConfig: {
maxAttempts: 3, // Maximum retry attempts
initialBackoffMs: 1000, // Initial backoff delay
maxBackoffMs: 10000, // Maximum backoff delay
backoffMultiplier: 2 // Exponential multiplier
}
});
// Automatically retries on network errors, rate limits, and transient failures
const response = await client.chat('Your message');
Features:
Example: See examples/with-retry.ts
Token bucket rate limiting to prevent hitting API limits.
import { ChatClient } from 'meloqui';
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
rateLimitConfig: {
requestsPerMinute: 60, // Max requests per minute
tokensPerMinute: 90000 // Max tokens per minute
}
});
// Requests automatically queued to stay within limits
const response = await client.chat('Your message');
Features:
Default Limits:
Example: See examples/with-rate-limiting.ts
Structured logging with configurable log levels for observability.
import { ChatClient, ConsoleLogger } from 'meloqui';
// Create logger with desired level
const logger = new ConsoleLogger({
level: 'debug' // 'debug' | 'info' | 'warn' | 'error'
});
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
logger
});
// All operations are logged with context
const response = await client.chat('Your message');
Log Levels:
debug: Verbose logging (request/response details, retry attempts)info: General operations (API calls, token usage)warn: Warnings (rate limit approaching, retries)error: Errors and failuresLogged Events:
Custom Loggers:
Implement the ILogger interface for custom logging:
import { ILogger } from 'meloqui';
class CustomLogger implements ILogger {
debug(message: string, context?: Record<string, unknown>): void {
// Your implementation
}
info(message: string, context?: Record<string, unknown>): void {
// Your implementation
}
warn(message: string, context?: Record<string, unknown>): void {
// Your implementation
}
error(message: string, error?: Error, context?: Record<string, unknown>): void {
// Your implementation
}
}
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
logger: new CustomLogger()
});
Example: See examples/with-logging.ts
Register and execute tools/functions for LLM integration.
import { ToolRegistry } from 'meloqui';
// Create registry
const registry = new ToolRegistry();
// Register a tool
registry.registerTool(
'getWeather',
async (location: string) => {
// Your implementation
return { temperature: 72, condition: 'sunny' };
},
{
description: 'Get current weather for a location'
}
);
// Execute directly
const result = await registry.executeTool('getWeather', 'Paris');
console.log(result); // { temperature: 72, condition: 'sunny' }
// Get all tools for LLM context
const tools = registry.getTools();
// Use with ChatClient for automatic tool calling
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
tools: registry
});
Features:
Tool Interface:
interface Tool {
name: string;
handler: ToolHandler;
metadata: {
description?: string;
[key: string]: unknown;
};
}
Example: See examples/with-tools.ts for both simple and agentic tool calling demonstrations.
Create your own provider to use any LLM:
import { ChatClient, ProviderPlugin } from 'meloqui';
class MyCustomProvider implements ProviderPlugin {
readonly name = 'my-provider';
readonly capabilities = {
chat: true,
streaming: true,
toolCalling: false,
vision: false,
audio: false
};
async chat(messages, options) {
// Your implementation here
return { content: 'Response', role: 'assistant' };
}
async *stream(messages, options) {
// Your streaming implementation
yield { content: 'Chunk', role: 'assistant' };
}
supportsTools() { return this.capabilities.toolCalling; }
supportsStreaming() { return this.capabilities.streaming; }
async chatWithTools(messages, tools, options) {
// Tool calling implementation (if supported)
return { content: 'Response', role: 'assistant' };
}
async *streamWithTools(messages, tools, options) {
// Streaming with tools (if supported)
yield { content: 'Chunk', role: 'assistant' };
}
}
// Use your custom provider
const provider = new MyCustomProvider();
const client = new ChatClient({ provider, model: 'my-model' });
const response = await client.chat('Hello!');
Features:
ProviderPlugin interfaceclient.capabilitiesCapability Validation:
The client validates capabilities before operations:
// If your provider has streaming: false
const client = new ChatClient({ provider, model: 'model' });
await client.stream('Hello'); // Throws CapabilityError
import { ChatClient } from 'meloqui';
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
apiKey: 'your-api-key' // Optional: defaults to OPENAI_API_KEY env var
});
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4',
// Authentication (recommended over apiKey)
auth: {
type: 'api-key',
apiKey: 'your-api-key'
},
// Custom base URL (for proxies or local models)
baseUrl: 'https://custom-endpoint.com/v1',
// Conversation tracking
conversationId: 'user-123-session-456'
});
const response = await client.chat('Your message', {
temperature: 0.7, // Sampling temperature (0-2)
maxTokens: 1000, // Maximum tokens to generate
topP: 0.9, // Nucleus sampling parameter
model: 'gpt-3.5-turbo' // Override default model
});
ChatClientMain client for interacting with LLM providers.
new ChatClient(config: ChatConfig)
Parameters:
config.provider: The LLM provider ('openai' |
'anthropic' |
'google' |
'ollama') |
config.model: The specific model to use (e.g., 'gpt-4', 'claude-3-opus')config.apiKey?: API key (optional, falls back to environment variable)config.auth?: Authentication configuration (recommended over apiKey)config.baseUrl?: Custom base URL for API requestsconfig.conversationId?: Optional conversation ID for trackingchat(message: string, options?: ChatOptions): Promise<ChatResponse>Send a chat message and get a response.
Parameters:
message: The user message to sendoptions?: Optional chat configurationReturns:
ChatResponse with content, role, and metadataExample:
const response = await client.chat('Hello!', { temperature: 0.7 });
console.log(response.content);
stream(message: string, options?: ChatOptions): AsyncIterator<StreamChunk>Stream a chat response for real-time output.
Parameters:
message: The user message to sendoptions?: Optional chat configurationReturns:
AsyncIterator<StreamChunk> yielding incremental response chunksExample:
for await (const chunk of client.stream('Tell me a story')) {
process.stdout.write(chunk.content);
}
getHistory(): Promise<Message[]>Retrieve the full conversation history for the current conversation.
Returns:
Message objects representing the conversationExample:
const history = await client.getHistory();
history.forEach(msg => {
console.log(`${msg.role}: ${msg.content}`);
});
clearHistory(): Promise<void>Clear the conversation history for the current conversation.
Example:
await client.clearHistory();
ChatResponseinterface ChatResponse {
content: string; // The generated response
role: 'assistant'; // Always 'assistant'
metadata?: {
model?: string; // Model that generated response
tokensUsed?: number; // Total tokens consumed
finishReason?: string; // Why generation stopped
};
}
ChatOptionsinterface ChatOptions {
temperature?: number; // 0-2, higher = more random
maxTokens?: number; // Max tokens to generate
topP?: number; // Nucleus sampling (0-1)
model?: string; // Override default model
}
Messageinterface Message {
role: 'user' | 'assistant' | 'system' | 'tool';
content: string;
name?: string; // For tool messages
toolCallId?: string; // For tool responses
}
See the examples directory for complete working examples:
To run examples:
# Set your API key
export OPENAI_API_KEY=your-key-here
# Core examples
npm run example:basic # Basic chat
npm run example:streaming # Streaming responses
npm run example:history # Conversation history
npm run example:storage # Persistent storage
# Enterprise examples
npm run example:retry # Retry logic
npm run example:rate-limit # Rate limiting
npm run example:logging # Structured logging
npm run example:tools # Tool system (no API key needed)
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Type checking
npm run typecheck
# Linting
npm run lint
# Build
npm run build
agent-chat/
├── src/
│ ├── client/ # ChatClient implementation
│ ├── providers/ # Provider implementations (OpenAI, etc.)
│ ├── types/ # TypeScript type definitions
│ └── index.ts # Public API exports
├── examples/ # Usage examples
├── dist/ # Compiled output
└── tests/ # Test files (colocated with source)
# All tests
npm test
# Watch mode
npm run test:watch
# Coverage
npm test -- --coverage
The SDK follows a layered architecture:
ChatClient (Public API)
↓
Provider Interface (IProvider)
↓
Provider Implementations (OpenAI, Anthropic, etc.)
↓
LangChain Integration
↓
LLM APIs
Contributions are welcome! We value all contributions, from bug reports to new features.
Before contributing, please read:
npm installSee CONTRIBUTING.md for detailed guidelines.
MIT License - see LICENSE for details.