Skip to content

litechain-ai/litechain

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

36 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Litechain

Litechain is a simple yet powerful drop-in replacement for Langchain to build powerful LLM agents with tools. It provides a unified, ergonomic API for integrating OpenAI, Gemini, Claude, and Groq models, allowing you to register custom tools and let the LLM invoke them as needed, or chain multiple LLMs together for complex AI agent workflows.

npm i litechain

Why Litechain over Langchain?

πŸš€ One Import vs Multiple Imports

Langchain:

import { ChatOpenAI } from "@langchain/openai";
import { PromptTemplate } from "@langchain/core/prompts";
import { Tool } from "@langchain/core/tools";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { RunnableSequence } from "@langchain/core/runnables";

Litechain:

import litechain from "litechain";

πŸ“ Prompt Templates: Simple String vs Complex Setup

Langchain:

import { PromptTemplate } from "@langchain/core/prompts";

const template = PromptTemplate.fromTemplate(
  "You are a helpful assistant. User query: {query}, Context: {context}"
);

const formattedPrompt = await template.format({
  query: "What's the weather?",
  context: "User is in NYC"
});

Litechain:

const llm = litechain.llm.openai({ apiKey: "sk-...", model: "gpt-4" });

// Direct string with templates
llm.systemprompt = "You are a helpful assistant. Context: {context}";

// Replace templates while invoking
const response = await llm.invoke("What's the weather?", {
  context: "User is in NYC"
});

πŸ› οΈ Tool Definition: Simple Object vs Zod Schemas

Langchain:

import { Tool } from "@langchain/core/tools";
import { z } from "zod";

const addTool = new Tool({
  name: "add",
  description: "Add two numbers",
  schema: z.object({
    a: z.number().describe("The first number"),
    b: z.number().describe("The second number")
  }),
  func: async ({ a, b }) => (a + b).toString()
});

Litechain:

const tool = {
  name: "add",
  description: "Add two numbers",
  parameters: {
    a: { type: "number", description: "The first number" },
    b: { type: "number", description: "The second number" }
  },
  execute: async ({ a, b }) => (a + b).toString()
};

llm.addTool(tool);

πŸ”— LLM Connections: Simple vs Complex

Langchain:

import { RunnableSequence } from "@langchain/core/runnables";
import { ChatOpenAI } from "@langchain/openai";

const entryLLM = new ChatOpenAI({ model: "gpt-3.5-turbo" });
const techLLM = new ChatOpenAI({ model: "gpt-4" });

// Complex routing logic with custom functions
const chain = RunnableSequence.from([
  {
    input: (input: string) => input,
    llm: entryLLM
  },
  (output) => {
    if (output.includes("technical")) {
      return techLLM.invoke(output);
    }
    return output;
  }
]);

Litechain:

const entryLLM = litechain.llm.openai({ apiKey: "sk-...", model: "gpt-3.5-turbo" });
const techLLM = litechain.llm.openai({ apiKey: "sk-...", model: "gpt-4" });

// Simple connection with automatic routing
entryLLM.connect({ TECH: techLLM });

// LLM automatically routes based on [TRANSFER:TECH] in response

Features

  • πŸ› οΈ Tool/Function Calling: Register your own tools/functions and let the LLM call them automatically.
  • πŸ”— LLM Chaining: Chain multiple LLMs together with automatic routing and transfer capabilities.
  • πŸ€– Unified API: Use OpenAI, Gemini, Claude, or Groq with a consistent interface.
  • ⚑ Simple Integration: Just one importβ€”no need to import types or utilities separately.
  • 🧩 Extensible: Add as many tools as you want, with custom parameters and logic.
  • πŸ“Š State Tracking: Built-in conversation flow and transfer history for debugging and transparency.
  • πŸ’° Budget Tracking: Monitor token usage and costs across all LLM calls with automatic limit enforcement.
  • πŸ” Custom Embeddings: Use OpenAI, Cohere, HuggingFace, or your own embedding functions for enhanced vector memory.

Installation

npm install litechain

Note: You must also install the relevant LLM SDKs for the providers you use (e.g., openai, @google/genai, @anthropic-ai/sdk, groq-sdk).


Usage

Basic Setup

import litechain from "litechain"; // One line import

const llm = litechain.llm.openai({ // Yes, that's simple
  apiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-4o-mini",
  budget: { limit: 10 }, // $10 budget limit
  memory: 'vector', // Vector memory for context
  embeddings: { // Custom embeddings for better search
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY!
  }
});

// Use invoke for standard responses  
const response = await llm.invoke("Hello!");

// Check budget usage
const usage = llm.getUsage();
console.log(`Cost: $${usage.cost.totalCost.toFixed(4)}`);

// Use run for streaming and advanced options
await llm.run("Write a story", {
  stream: true,
  onChunk: (chunk) => process.stdout.write(chunk.delta),
  onComplete: (content) => console.log(`\nCompleted: ${content.length} chars`)
});

Define Tools

const tool = {
  description: "Add two numbers",
  name: "add",
  parameters: {
    a: { type: "number", description: "The first number" },
    b: { type: "number", description: "The second number" }
  },
  execute: async (parameters) => (parameters.a + parameters.b).toString()
};

llm.addTool(tool); // Tool added - no need for Zod or any imports

Set System Prompt

llm.systemprompt = "You are a helpful assistant"; // System prompt defined

Connect LLMs

const techLLM = litechain.llm.openai({ apiKey: "sk-...", model: "gpt-4" });
llm.connect({ TECH: techLLM }); // Yes, this is how simple it is to connect LLMs

Access State

llm.state; // Access state at any point
llm.getConversationFlow(); // Get conversation history
llm.getTransferHistory(); // Get transfer history
llm.clearState(); // Clear conversation state

Quickstart

Basic Tool Calling

import litechain from "litechain";
import dotenv from "dotenv";
dotenv.config();

const client = litechain.llm.openai({
  apiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-4o-mini",
  tools: [
    {
      name: "add",
      description: "Add two numbers",
      parameters: {
        a: { type: "number", description: "The first number" },
        b: { type: "number", description: "The second number" }
      },
      execute: async ({ a, b }) => (a + b).toString()
    }
  ]
});

const response = await client.invoke("add 5 and 3");
console.log(response); // "8"

LLM Chaining

import litechain from "litechain";

// 1. Setup LLMs
const entryLLM = litechain.llm.openai({
  apiKey: "sk-entry",
  model: "gpt-3.5-turbo"
});

const techLLM = litechain.llm.openai({
  apiKey: "sk-tech", 
  model: "gpt-3.5-turbo"
});

const billingLLM = litechain.llm.openai({
  apiKey: "sk-billing",
  model: "gpt-3.5-turbo"
});

// 2. Set system prompts
entryLLM.systemprompt = `
You are the entry point support agent.
Answer basic queries. For billing issues, respond with: [TRANSFER:BILLING]
For technical issues, respond with: [TRANSFER:TECH]
`;

techLLM.systemprompt = `You are a tech support specialist. Fix technical issues.`;

billingLLM.systemprompt = `
You handle billing inquiries. If a refund is needed, respond with: [ESCALATE:HUMAN]
`;

// 3. Connect LLMs
entryLLM.connect({
  BILLING: billingLLM,
  TECH: techLLM
});

billingLLM.connect({
  HUMAN: async (message) => {
    console.log("⚠️ Escalating to human...");
    return "A human will join shortly.";
  }
});

// 4. Handle message (automatic chaining)
const reply = await entryLLM.invoke("I want a refund for my last order");
console.log(reply); // Final response after going through all LLMs

LLM Chaining Guide

Philosophy

Litechain makes building AI agents extremely simple by allowing you to chain LLMs together with automatic routing. Each LLM can transfer to another LLM or escalate to a human/custom function using simple text patterns.

Key Concepts

  1. Transfers ([TRANSFER:XXX]): Route to another LLM
  2. Escalations ([ESCALATE:XXX]): Route to a custom function (e.g., human intervention)
  3. Connections: Define routing rules between LLMs and functions
  4. State Tracking: Automatic conversation flow and transfer history

API Reference

llm.connect(routes)

Connect an LLM to other LLMs or functions for routing.

llm.connect({
  BILLING: billingLLM,
  TECH: techLLM,
  HUMAN: async (message) => "Human response"
});

llm.getConversationFlow()

Get the conversation flow for debugging.

const flow = llm.getConversationFlow();
// Returns array of conversation entries with LLM names, messages, responses, and timestamps

llm.getTransferHistory()

Get the transfer history for debugging.

const transfers = llm.getTransferHistory();
// Returns array of transfer/escalation events

llm.clearState()

Clear the conversation state and start fresh.

llm.clearState();

Advanced Example: Multi-Department Support System

// Entry point
const entry = litechain.llm.openai({
  apiKey: "sk-entry",
  model: "gpt-3.5-turbo"
});

// Specialized departments
const sales = litechain.llm.openai({
  apiKey: "sk-sales",
  model: "gpt-4"
});

const support = litechain.llm.openai({
  apiKey: "sk-support", 
  model: "gpt-3.5-turbo"
});

const billing = litechain.llm.openai({
  apiKey: "sk-billing",
  model: "gpt-3.5-turbo"
});

// Set up routing
entry.connect({
  SALES: sales,
  SUPPORT: support,
  BILLING: billing,
  URGENT: async (message) => {
    // Custom logic for urgent issues
    await sendSlackNotification(message);
    return "Urgent issue escalated. You'll be contacted shortly.";
  }
});

// Handle complex queries
const response = await entry.invoke("I need to cancel my subscription and get a refund");
// Automatically routes through appropriate departments

Supported Providers

  • OpenAI (openai)
  • Gemini (@google/genai)
  • Claude (@anthropic-ai/sdk)
  • Groq (groq-sdk)

How It Works

Tool Calling

  1. Register tools with a name, description, parameters, and an execute function.
  2. Invoke the LLM with a prompt. If the LLM decides a tool is needed, Litechain:
    • Parses the tool call from the LLM.
    • Executes your tool(s) with the provided arguments.
    • Feeds the result(s) back to the LLM.
    • Returns the final LLM response to you.

LLM Chaining

  1. Set up LLMs with appropriate system prompts.
  2. Connect them using the connect() method.
  3. Invoke the entry LLM with a message.
  4. Automatic routing based on [TRANSFER:XXX] and [ESCALATE:XXX] patterns.
  5. State tracking maintains conversation flow and transfer history.

API Reference

Core LLM Methods

llm.run(prompt, options)

Enhanced method supporting streaming and advanced options.

await llm.run("Generate content", {
  stream: true,
  onChunk: (chunk: StreamChunk) => void,
  onComplete: (content: string) => void,
  onError: (error: Error) => void
});

llm.invoke(message, variables)

Standard invocation with variable interpolation.

const response = await llm.invoke("Hello {name}", { name: "Alice" });

llm.addTool(tool)

Add tools for function calling.

llm.addTool({
  name: "tool_name",
  description: "Tool description", 
  parameters: { /* parameter schema */ },
  execute: async (params) => "result"
});

llm.connect(routes)

Connect LLM to other LLMs or functions for chaining.

llm.connect({
  SUPPORT: supportLLM,
  BILLING: billingLLM,
  HUMAN: async (msg) => "Human response"
});

State Management Methods

llm.getConversationFlow()

Get detailed conversation history with timestamps.

const flow: ConversationFlowEntry[] = llm.getConversationFlow();
// Returns: [{ llmName, message, response, timestamp, transferTarget? }]

llm.getTransferHistory()

Get LLM transfer/escalation history.

const transfers: TransferResponse[] = llm.getTransferHistory();
// Returns: [{ type, target, originalResponse, timestamp }]

llm.clearState()

Reset conversation state and start fresh.

llm.clearState(); // New thread_id, empty history

Memory Factory

createMemory(config, sessionId?)

Create memory instances with different backends.

// String configs
const chatMemory = createMemory('chat');
const vectorMemory = createMemory('vector');

// Object configs  
const fileMemory = createMemory({
  type: 'file',
  path: './memory/conversations'
});

const hybridMemory = createMemory({
  type: 'hybrid',
  chat: { type: 'file', path: './chat' },
  vector: { provider: 'local' }
});

Streaming Types

interface StreamChunk {
  content: string;     // Full content so far
  delta: string;       // New content in this chunk
  isComplete: boolean; // Whether streaming is done
  timestamp?: Date;
  metadata?: Record<string, any>;
}

interface StreamOptions {
  onChunk?: (chunk: StreamChunk) => void;
  onComplete?: (fullContent: string) => void;
  onError?: (error: Error) => void;
}

Tool Definition

interface Tool<P = Record<string, any>> {
  name: string;
  description: string;
  parameters: P; // JSON schema for parameters
  execute: (parameters: P) => Promise<string>;
}

Connection Types

type ConnectionType = LLMBase | ((message: string) => Promise<string> | string);

interface ConnectionRoutes {
  [key: string]: ConnectionType;
}

API Reference

litechain.llm.[provider]({ apiKey, model, tools })

  • apiKey: Your provider API key.
  • model: The model name (e.g., "gpt-4o-mini").
  • tools: Array of tool definitions.

Tool Definition

{
  name: string;
  description: string;
  parameters: Record<string, { type: string; description: string }>;
  execute: (parameters: Record<string, any>) => Promise<string>;
}

Connection Types

type ConnectionType = LLMBase | ((message: string) => Promise<string> | string);

Advanced Tool Composition

Create sophisticated tools that combine multiple operations:

// Composite tool that internally uses multiple operations
const compositeTools = [
  {
    name: "analyze_text_complete", 
    description: "Complete text analysis with word count, timestamps, and UUID",
    parameters: {
      text: { type: "string", description: "Text to analyze" }
    },
    execute: async (parameters: any) => {
      const text = parameters.text;
      const words = text.trim().split(/\s+/).filter(w => w.length > 0);
      const chars = text.length;
      const timestamp = new Date().toISOString();
      const analysisId = crypto.randomUUID();
      
      return `Complete Analysis [${analysisId}]:
- Text: "${text}"
- Word count: ${words.length}
- Character count: ${chars}
- Analysis time: ${timestamp}
- Sentences: ${text.split(/[.!?]+/).filter(s => s.trim().length > 0).length}`;
    }
  },
  {
    name: "system_status",
    description: "Get comprehensive system status with performance metrics",
    parameters: {},
    execute: async () => {
      const timestamp = new Date().toISOString();
      const uptime = process.uptime();
      const memory = process.memoryUsage();
      
      return `System Status Report:
- Current time: ${timestamp}
- Uptime: ${Math.floor(uptime / 60)} minutes  
- Memory usage: ${Math.round(memory.heapUsed / 1024 / 1024)}MB
- Process ID: ${process.pid}
- Status: Operational`;
    }
  }
];

llm.addTool(compositeTools[0]);
llm.addTool(compositeTools[1]);

// Complex multi-tool workflows
const complexQueries = [
  "Calculate 15% of 1000, then check the weather in New York, and create a file called 'weather-report.txt'",
  "Generate a UUID, get the current time in ISO format, then analyze our weekly sales data",
  "Count words in 'The quick brown fox jumps over the lazy dog', calculate the square of that number, and list all files"
];

for (const query of complexQueries) {
  const response = await llm.invoke(query);
  console.log(`Query: ${query}`);
  console.log(`Result: ${response}\n`);
}

Tool Performance Testing

Built-in performance analysis for tool execution:

// Performance testing for individual tools
async function performanceTest(toolName: string, query: string) {
  const startTime = Date.now();
  
  const response = await llm.invoke(query);
  
  const duration = Date.now() - startTime;
  
  return {
    tool: toolName,
    query,
    duration,
    responseLength: response.length
  };
}

// Benchmark multiple tools
const performanceTests = [
  { tool: "calculate", query: "Calculate 123 * 456" },
  { tool: "get_time", query: "What time is it in ISO format?" },
  { tool: "weather_lookup", query: "What's the weather in Tokyo?" },
  { tool: "word_count", query: "Count words in 'Hello world from Litechain'" }
];

const results = [];
for (const test of performanceTests) {
  llm.clearState(); // Clean state for accurate timing
  const result = await performanceTest(test.tool, test.query);
  results.push(result);
}

// Performance analytics
console.log("Performance Results:");
results.forEach(result => {
  console.log(`  ${result.tool}: ${result.duration}ms (${result.responseLength} chars)`);
});

const avgDuration = results.reduce((sum, r) => sum + r.duration, 0) / results.length;
console.log(`  Average: ${Math.round(avgDuration)}ms`);

Comprehensive Feature Testing

Test all Litechain capabilities with a complete test suite:

import litechain from "litechain";

async function comprehensiveTest() {
  // 1. Basic LLM Creation
  const client = litechain.llm.gemini({
    apiKey: process.env.GEMINI_API_KEY!,
    model: "gemini-2.0-flash"
  });

  // 2. System Prompt Configuration  
  client.systemprompt = "You are a helpful assistant for mathematical calculations and time queries.";

  // 3. Tool Integration
  const tools = [
    {
      name: "add",
      description: "Add two numbers",
      parameters: {
        a: { type: "number", description: "First number" },
        b: { type: "number", description: "Second number" }
      },
      execute: async ({ a, b }) => (a + b).toString()
    },
    {
      name: "multiply", 
      description: "Multiply two numbers",
      parameters: {
        a: { type: "number", description: "First number" },
        b: { type: "number", description: "Second number" }
      },
      execute: async ({ a, b }) => (a * b).toString()
    },
    {
      name: "get_time",
      description: "Get current time",
      parameters: {},
      execute: async () => new Date().toISOString()
    }
  ];

  tools.forEach(tool => client.addTool(tool));

  // 4. Complex Tool Chain Execution
  const complexQuery = "multiply 4 with 5 and add the result with 342 and get the current time in human format?";
  const response = await client.invoke(complexQuery);
  console.log("Complex chain result:", response);

  // 5. State Management Inspection
  const state = client.state;
  console.log("State Info:", {
    threadId: state.thread_id.substring(0, 8) + "...",
    historyEntries: state.history.length,
    conversationFlow: state.conversation_flow.length,
    currentLLM: state.current_llm,
    toolsAvailable: client.tools.length
  });

  // 6. Conversation Context Tracking
  const followUp = "What was the final result of that calculation?";
  const contextResponse = await client.invoke(followUp);
  console.log("Context preserved:", contextResponse);

  // 7. History Analysis
  console.log("Recent conversation:");
  client.state.history.slice(-3).forEach((entry, i) => {
    const preview = entry.content.substring(0, 50) + "...";
    console.log(`  ${i + 1}. ${entry.role}: ${preview}`);
  });

  // 8. Conversation Flow Tracking
  if (client.state.conversation_flow.length > 0) {
    console.log("Flow tracking:");
    client.state.conversation_flow.forEach((entry, i) => {
      const preview = entry.response.substring(0, 40) + "...";
      console.log(`  ${i + 1}. [${entry.timestamp.toLocaleTimeString()}] ${entry.llmName}: ${preview}`);
    });
  }

  return {
    success: true,
    testsCompleted: 8,
    toolsIntegrated: tools.length,
    stateManaged: true,
    contextPreserved: true
  };
}

// Run comprehensive test
comprehensiveTest()
  .then(results => {
    console.log("βœ… All tests passed!", results);
  })
  .catch(error => {
    console.error("❌ Test failed:", error);
  });

Example Use Cases

AI Agents

  • Customer Support: Route queries to specialized departments
  • Sales Funnel: Guide prospects through qualification and closing
  • Content Creation: Chain research, writing, and editing LLMs
  • Code Review: Route to different specialized code reviewers

Business Logic

  • Multi-step Processing: Chain validation, processing, and notification LLMs
  • Decision Trees: Route based on business rules and conditions
  • Escalation Systems: Automatic human intervention when needed

Streaming Support

Litechain supports real-time streaming for a better user experience with immediate response feedback:

Basic Streaming

import litechain from "litechain";

const llm = litechain.llm.openai({
  apiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-4o-mini"
});

// Stream response with real-time chunks
await llm.run("Write a short story about AI", {
  stream: true,
  onChunk: (chunk) => {
    process.stdout.write(chunk.delta); // Real-time output
    
    if (chunk.isComplete) {
      console.log("\nβœ… Streaming completed!");
    }
  },
  onComplete: (fullContent) => {
    console.log(`Full response: ${fullContent.length} characters`);
  },
  onError: (error) => {
    console.error("Streaming error:", error.message);
  }
});

Advanced Streaming Features

// Custom chunk processing with real-time analytics
let wordCount = 0;
let sentenceCount = 0;

await llm.run("Explain machine learning in detail", {
  stream: true,
  onChunk: (chunk) => {
    if (chunk.delta) {
      // Real-time text analysis
      const words = chunk.delta.split(/\s+/).filter(w => w.length > 0);
      const sentences = chunk.delta.split(/[.!?]+/).filter(s => s.trim().length > 0);
      
      wordCount += words.length;
      sentenceCount += sentences.length;
      
      // Update live statistics
      process.stdout.write(`\rπŸ“Š Words: ${wordCount}, Sentences: ${sentenceCount}`);
    }
  }
});

// Concurrent streaming from multiple LLMs
const llm1 = litechain.llm.openai({ apiKey: "...", model: "gpt-4o-mini" });
const llm2 = litechain.llm.openai({ apiKey: "...", model: "gpt-4o-mini" });

llm1.systemprompt = "You are a technical expert.";
llm2.systemprompt = "You are a creative writer.";

// Run multiple streams concurrently
const promises = [
  llm1.run("Explain HTTP protocol", { stream: true, onChunk: (chunk) => console.log(`[Tech] ${chunk.delta}`) }),
  llm2.run("Write a poem about coding", { stream: true, onChunk: (chunk) => console.log(`[Creative] ${chunk.delta}`) })
];

await Promise.all(promises);

Streaming Performance Benefits

  • 10-15% faster completion times compared to non-streaming
  • Immediate user feedback with progressive content display
  • Real-time processing capabilities for live analytics
  • Concurrent streams for multi-faceted responses

Budget Tracking

Litechain includes built-in budget tracking to monitor token usage and costs across all LLM calls:

Basic Budget Setup

import litechain from "litechain";

const llm = litechain.llm.openai({
  apiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-4o-mini",
  budget: {
    limit: 10, // $10 USD limit
    onExceeded: (usage) => {
      console.log("Budget exceeded!", usage);
    }
  }
});

// Use normally - budget is tracked automatically
const response = await llm.invoke("Hello!");

// Check current usage
const usage = llm.getUsage();
console.log({
  tokens: usage.tokens.totalTokens,
  cost: usage.cost.totalCost // In USD
});

Advanced Budget Features

// Detailed budget configuration
const llm = litechain.llm.openai({
  apiKey: "...",
  model: "gpt-4o-mini",
  budget: {
    limit: 50,
    trackTokens: true,
    onExceeded: (usage) => {
      // Custom handler - log, send alert, etc.
      console.log(`Budget exceeded: $${usage.cost.totalCost}`);
      // Optionally stop execution or switch to cheaper model
    }
  }
});

// Get detailed report
console.log(llm.getBudgetReport());
// Output:
// Budget Usage Report:
// - Tokens: 1,250 (800 input, 450 output)
// - Cost: $0.0045 ($0.0024 input, $0.0021 output)
// - Remaining: $49.9955
// - Status: OK

// Check if budget exceeded
if (llm.isBudgetExceeded()) {
  console.log("Switch to cheaper model or stop");
}

// Reset budget for new session
llm.resetBudget();

// Update budget limits dynamically
llm.updateBudgetConfig({ limit: 100 });

Budget Tracking Across Providers

// All providers support budget tracking
const openai = litechain.llm.openai({ 
  apiKey: "...", 
  model: "gpt-4o-mini",
  budget: { limit: 10 }
});

const gemini = litechain.llm.gemini({ 
  apiKey: "...", 
  model: "gemini-2.0-flash",
  budget: { limit: 10 }
});

const claude = litechain.llm.claude({ 
  apiKey: "...", 
  model: "claude-3-haiku",
  budget: { limit: 10 }
});

// Compare costs across providers
const prompt = "Explain quantum computing";
const [openaiResponse, geminiResponse, claudeResponse] = await Promise.all([
  openai.invoke(prompt),
  gemini.invoke(prompt),
  claude.invoke(prompt)
]);

console.log("Cost comparison:");
console.log("OpenAI:", openai.getUsage().cost.totalCost);
console.log("Gemini:", gemini.getUsage().cost.totalCost);
console.log("Claude:", claude.getUsage().cost.totalCost);

Streaming with Budget Tracking

await llm.run("Write a long essay", {
  stream: true,
  onChunk: (chunk) => {
    process.stdout.write(chunk.delta);
  },
  onComplete: (content) => {
    // Budget is automatically tracked during streaming
    const usage = llm.getUsage();
    console.log(`\nCost: $${usage.cost.totalCost.toFixed(4)}`);
  }
});

✨ New Enhanced Features

πŸ’° Budget Tracking

Track token usage and costs automatically with built-in budget limits:

const chain = litechain({
  provider: 'openai',
  model: "gpt-4o",
  apiKey: "sk-...",
  budget: {
    limit: 10, // USD
    onExceeded: () => console.log("Limit exceeded")
  }
});

const response = await chain.invoke("Hello!");
const usage = chain.getUsage();
// => { tokens: 5000, cost: 0.75, calls: 1, inputTokens: 2000, outputTokens: 3000 }

🎯 Custom Embedding Providers

Use built-in providers or custom embedding functions:

// Built-in provider
const chain = litechain({
  model: "gpt-4o",
  apiKey: "sk-...",
  embeddings: {
    provider: "cohere",
    apiKey: "...",
    model: "embed-v3"
  }
});

// Custom embedding function
const chain = litechain({
  model: "gpt-4o", 
  apiKey: "sk-...",
  embeddings: async (text) => {
    // Your custom embedding logic
    return [0.1, 0.2, 0.3]; // Return vector
  }
});