CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-langchain--openai

OpenAI integrations for LangChain.js providing chat models, embeddings, tools, and Azure support.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

tools.mddocs/

Tools

Image generation with DALL-E and custom tool creation for the OpenAI Responses API. Extend model capabilities with external functions and specialized tools.

Capabilities

DallEAPIWrapper Class

DALL-E image generation tool for creating images from text descriptions.

/**
 * DALL-E image generation tool
 * Creates images from text descriptions using OpenAI's DALL-E models
 */
class DallEAPIWrapper extends Tool {
  
  constructor(fields?: Partial<DallEAPIWrapperParams>);

  /** Tool identification */
  name: string; // "dalle_image_generator"
  description: string; // "A tool for generating images from text descriptions"

  /** Model configuration */
  model: string; // Default: "dall-e-3"
  style: "natural" | "vivid"; // Image style (default: "vivid")
  quality: "standard" | "hd"; // Image quality (default: "standard")
  n: number; // Number of images to generate (default: 1)
  size: string; // Image size (default: "1024x1024")
  dallEResponseFormat: "url" | "b64_json"; // Response format (default: "url")

  /** Client configuration */
  openAIApiKey?: string; // OpenAI API key
  organization?: string; // OpenAI organization ID
  baseURL?: string; // Custom base URL
  timeout?: number; // Request timeout
  maxRetries?: number; // Maximum retry attempts

  /** Generate image(s) from text description */
  _call(input: string): Promise<string>;

  /** Make image generation requests with retry logic */
  imageGenerationWithRetry<T>(
    request: OpenAIClient.Images.ImageGenerateParams,
    options?: OpenAICallOptions
  ): Promise<T>;
}

DallE Parameters Interface

Configuration interface for DALL-E API wrapper.

interface DallEAPIWrapperParams {
  /** DALL-E model version */
  model: string;
  
  /** Image generation style */
  style: "natural" | "vivid";
  
  /** Image quality level */
  quality: "standard" | "hd";
  
  /** Number of images to generate */
  n: number;
  
  /** Image dimensions */
  size: string;
  
  /** Response format for generated images */
  dallEResponseFormat: "url" | "b64_json";
  
  /** OpenAI API configuration */
  openAIApiKey?: string;
  organization?: string;
  baseURL?: string;
  timeout?: number;
  maxRetries?: number;
}

Custom Tool Creation

Create custom tools for use with OpenAI's Responses API.

/**
 * Create custom tools for OpenAI Responses API
 * Converts LangChain runnables into OpenAI-compatible tool definitions
 */
function customTool(
  func: RunnableFunc<string, string, ToolRunnableConfig>,
  fields: CustomToolFields
): DynamicTool<string>;

type CustomToolFields = Omit<OpenAI.Responses.CustomTool, "type">;

Usage Examples

Basic DALL-E Image Generation

import { DallEAPIWrapper } from "@langchain/openai";

const dalleGenerator = new DallEAPIWrapper({
  model: "dall-e-3",
  apiKey: process.env.OPENAI_API_KEY,
  quality: "hd",
  size: "1024x1024",
  style: "vivid"
});

// Generate a single image
const imageUrl = await dalleGenerator._call(
  "A futuristic city skyline at sunset with flying cars and neon lights"
);
console.log("Generated image URL:", imageUrl);

// The returned URL can be used to display or download the image

Different DALL-E Models and Configurations

// DALL-E 3 (recommended) - high quality, single image
const dalleV3 = new DallEAPIWrapper({
  model: "dall-e-3",
  quality: "hd", // "standard" or "hd"
  style: "natural", // "natural" or "vivid"
  size: "1024x1792", // Portrait orientation
  dallEResponseFormat: "url"
});

// DALL-E 2 - can generate multiple images
const dalleV2 = new DallEAPIWrapper({
  model: "dall-e-2",
  n: 4, // Generate 4 images (DALL-E 2 only)
  size: "512x512", // Smaller size for DALL-E 2
  quality: "standard" // HD not available for DALL-E 2
});

// Generate multiple images with DALL-E 2
const multipleImages = await dalleV2._call(
  "A cute robot playing with a cat in a garden"
);
console.log("Multiple image URLs:", multipleImages);

Supported Image Sizes

// DALL-E 3 supported sizes
const dalle3Sizes = ["1024x1024", "1792x1024", "1024x1792"];

// DALL-E 2 supported sizes  
const dalle2Sizes = ["256x256", "512x512", "1024x1024"];

// Create generators for different aspect ratios
const squareGenerator = new DallEAPIWrapper({
  model: "dall-e-3",
  size: "1024x1024" // Square
});

const landscapeGenerator = new DallEAPIWrapper({
  model: "dall-e-3", 
  size: "1792x1024" // Landscape
});

const portraitGenerator = new DallEAPIWrapper({
  model: "dall-e-3",
  size: "1024x1792" // Portrait
});

Base64 Response Format

const dalle64 = new DallEAPIWrapper({
  model: "dall-e-3",
  dallEResponseFormat: "b64_json", // Return base64 encoded image
  quality: "hd"
});

const base64Image = await dalle64._call("A serene mountain landscape");

// Convert base64 to buffer for saving
const imageBuffer = Buffer.from(base64Image, 'base64');

// Save to file (Node.js)
import { writeFileSync } from 'fs';
writeFileSync('generated_image.png', imageBuffer);

// Or use in web applications
const dataUrl = `data:image/png;base64,${base64Image}`;
// dataUrl can be used directly in <img> tags

Custom Tool Creation

import { customTool } from "@langchain/openai";
import { z } from "zod";

// Create a weather tool
const weatherTool = customTool(
  async (input: string) => {
    // Parse the input (it will be JSON string from the model)
    const { location, units } = JSON.parse(input);
    
    // Simulate weather API call
    const temperature = Math.floor(Math.random() * 30) + 10;
    const condition = ["sunny", "cloudy", "rainy"][Math.floor(Math.random() * 3)];
    
    return JSON.stringify({
      location,
      temperature: `${temperature}°${units === 'celsius' ? 'C' : 'F'}`,
      condition,
      timestamp: new Date().toISOString()
    });
  },
  {
    name: "get_weather",
    description: "Get current weather information for a specific location",
    schema: z.object({
      location: z.string().describe("City name or location"),
      units: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("Temperature units")
    })
  }
);

// Create a calculator tool
const calculatorTool = customTool(
  async (input: string) => {
    const { operation, a, b } = JSON.parse(input);
    
    let result: number;
    switch (operation) {
      case "add": result = a + b; break;
      case "subtract": result = a - b; break;
      case "multiply": result = a * b; break;
      case "divide": result = b !== 0 ? a / b : NaN; break;
      default: throw new Error(`Unknown operation: ${operation}`);
    }
    
    return JSON.stringify({ result, operation, operands: [a, b] });
  },
  {
    name: "calculator",
    description: "Perform basic mathematical operations",
    schema: z.object({
      operation: z.enum(["add", "subtract", "multiply", "divide"]),
      a: z.number().describe("First number"),
      b: z.number().describe("Second number")
    })
  }
);

Using Custom Tools with Chat Models

import { ChatOpenAI } from "@langchain/openai";

// Create chat model that supports Responses API
const chatModel = new ChatOpenAI({
  model: "gpt-4o",
  temperature: 0,
  useResponsesApi: true // Required for custom tools
});

// Bind custom tools to the model
const modelWithCustomTools = chatModel.bindTools([
  weatherTool,
  calculatorTool
]);

// The model can now call these custom tools
const response = await modelWithCustomTools.invoke(
  "What's the weather in Tokyo? Also, what's 15 multiplied by 23?"
);

console.log("Model response:", response.content);

// Handle tool calls if any
if (response.tool_calls && response.tool_calls.length > 0) {
  for (const toolCall of response.tool_calls) {
    console.log(`Called tool: ${toolCall.name}`);
    console.log(`With args: ${JSON.stringify(toolCall.args)}`);
  }
}

Advanced Custom Tool Example

// Database search tool with complex schema
const databaseSearchTool = customTool(
  async (input: string) => {
    const { query, filters, limit, sortBy } = JSON.parse(input);
    
    // Simulate database search
    const mockResults = Array.from({ length: Math.min(limit, 5) }, (_, i) => ({
      id: i + 1,
      title: `Result ${i + 1} for "${query}"`,
      score: Math.random(),
      category: filters?.category || "general",
      timestamp: new Date(Date.now() - Math.random() * 86400000).toISOString()
    }));
    
    // Sort results
    if (sortBy === "score") {
      mockResults.sort((a, b) => b.score - a.score);
    } else if (sortBy === "date") {
      mockResults.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
    }
    
    return JSON.stringify({
      results: mockResults,
      total: mockResults.length,
      query,
      filters
    });
  },
  {
    name: "search_database",
    description: "Search the company database with advanced filtering and sorting",
    schema: z.object({
      query: z.string().describe("Search query string"),
      filters: z.object({
        category: z.string().optional().describe("Filter by category"),
        dateRange: z.object({
          start: z.string().optional().describe("Start date (ISO format)"),
          end: z.string().optional().describe("End date (ISO format)")
        }).optional().describe("Date range filter")
      }).optional().describe("Search filters"),
      limit: z.number().default(10).describe("Maximum number of results"),
      sortBy: z.enum(["relevance", "date", "score"]).default("relevance").describe("Sort order")
    })
  }
);

// File processing tool
const fileProcessorTool = customTool(
  async (input: string) => {
    const { fileName, operation, options } = JSON.parse(input);
    
    // Simulate file processing
    const operations = {
      analyze: () => ({ type: "text", lines: 150, words: 2340, size: "12KB" }),
      compress: () => ({ originalSize: "12KB", compressedSize: "8KB", ratio: "33%" }),
      convert: () => ({ from: "docx", to: options.format, status: "completed" })
    };
    
    const result = operations[operation as keyof typeof operations]?.() || 
      { error: "Unknown operation" };
    
    return JSON.stringify({
      fileName,
      operation,
      result,
      timestamp: new Date().toISOString()
    });
  },
  {
    name: "process_file",
    description: "Process files with various operations like analysis, compression, or conversion",
    schema: z.object({
      fileName: z.string().describe("Name of the file to process"),
      operation: z.enum(["analyze", "compress", "convert"]).describe("Operation to perform"),
      options: z.object({
        format: z.string().optional().describe("Target format for conversion"),
        quality: z.enum(["low", "medium", "high"]).optional().describe("Quality level")
      }).optional().describe("Additional operation options")
    })
  }
);

Error Handling with Tools

// Robust tool with error handling
const apiTool = customTool(
  async (input: string) => {
    try {
      const { endpoint, method, data } = JSON.parse(input);
      
      // Simulate API call
      if (endpoint === "/error") {
        throw new Error("API endpoint not found");
      }
      
      return JSON.stringify({
        status: "success",
        endpoint,
        method,
        response: { message: "API call successful", data }
      });
      
    } catch (error) {
      return JSON.stringify({
        status: "error",
        error: error instanceof Error ? error.message : "Unknown error",
        timestamp: new Date().toISOString()
      });
    }
  },
  {
    name: "api_call",
    description: "Make API calls to external services",
    schema: z.object({
      endpoint: z.string().describe("API endpoint URL"),
      method: z.enum(["GET", "POST", "PUT", "DELETE"]).default("GET").describe("HTTP method"),
      data: z.record(z.any()).optional().describe("Request payload")
    })
  }
);

// Test error handling
const chatWithErrorHandling = new ChatOpenAI({
  model: "gpt-4o",
  useResponsesApi: true
}).bindTools([apiTool]);

const errorResponse = await chatWithErrorHandling.invoke(
  "Make a GET request to /error endpoint"
);

Combining DALL-E with Custom Tools

// Create a comprehensive creative assistant
const imageDescriptionTool = customTool(
  async (input: string) => {
    const { imageUrl, analysisType } = JSON.parse(input);
    
    // Simulate image analysis (in real app, use vision API)
    const analyses = {
      artistic: "This image shows vibrant colors with impressionist style brushstrokes...",
      technical: "Resolution: 1024x1024, Color depth: 24-bit, Format: PNG...",
      content: "The image depicts a futuristic cityscape with neon lighting..."
    };
    
    return JSON.stringify({
      analysis: analyses[analysisType as keyof typeof analyses] || "General analysis not available",
      imageUrl,
      analysisType
    });
  },
  {
    name: "analyze_image", 
    description: "Analyze generated images for artistic, technical, or content details",
    schema: z.object({
      imageUrl: z.string().describe("URL of the image to analyze"),
      analysisType: z.enum(["artistic", "technical", "content"]).describe("Type of analysis to perform")
    })
  }
);

// Creative assistant with image generation and analysis
const creativeAssistant = new ChatOpenAI({
  model: "gpt-4o",
  useResponsesApi: true
}).bindTools([imageDescriptionTool]);

// Also create DALL-E wrapper for image generation
const imageGenerator = new DallEAPIWrapper({
  model: "dall-e-3",
  quality: "hd",
  style: "vivid"
});

// Workflow: generate image, then analyze it
async function createAndAnalyze(prompt: string) {
  console.log("Generating image...");
  const imageUrl = await imageGenerator._call(prompt);
  
  console.log("Analyzing image...");
  const analysis = await creativeAssistant.invoke(
    `Analyze this generated image with artistic analysis: ${imageUrl}`
  );
  
  return { imageUrl, analysis: analysis.content };
}

const result = await createAndAnalyze(
  "A majestic dragon soaring over a crystal castle in a fantasy landscape"
);

Tool Utilities

Built-in Tool Detection

import { 
  isBuiltInTool, 
  isCustomTool,
  parseCustomToolCall,
  convertCompletionsCustomTool,
  convertResponsesCustomTool 
} from "@langchain/openai";

// Check tool types
const customWeatherTool = customTool(/* ... */);
const builtInTool = { type: "code_interpreter" };

console.log(isCustomTool(customWeatherTool)); // true
console.log(isBuiltInTool(builtInTool)); // true

// Convert between API formats
const completionsFormat = convertResponsesCustomTool(customWeatherTool);
const responsesFormat = convertCompletionsCustomTool(completionsFormat);

Tool Conversion Utilities

import { 
  formatToOpenAIFunction,
  formatToOpenAITool,
  formatToOpenAIAssistantTool 
} from "@langchain/openai";
import { StructuredTool } from "@langchain/core/tools";

// Convert LangChain tools to OpenAI formats
class WeatherTool extends StructuredTool {
  name = "get_weather";
  description = "Get weather information";
  
  schema = z.object({
    location: z.string()
  });

  async _call(args: { location: string }) {
    return `Weather in ${args.location}: Sunny, 25°C`;
  }
}

const weatherTool = new WeatherTool();

// Convert to different OpenAI tool formats
const functionFormat = formatToOpenAIFunction(weatherTool);
const toolFormat = formatToOpenAITool(weatherTool);  
const assistantFormat = formatToOpenAIAssistantTool(weatherTool);

console.log("Function format:", functionFormat);
console.log("Tool format:", toolFormat);
console.log("Assistant format:", assistantFormat);

Best Practices

Image Generation Guidelines

// Best practices for DALL-E prompts
const imageGenerator = new DallEAPIWrapper({
  model: "dall-e-3",
  quality: "hd",
  style: "vivid"
});

// Good prompt structure
const goodPrompts = [
  "A photorealistic portrait of a wise elderly wizard with a long white beard, wearing star-covered robes, in a mystical library with floating books and magical glowing orbs",
  
  "Vector art style illustration of a modern coffee shop interior with plants, wooden furniture, large windows showing city view, warm lighting, isometric perspective",
  
  "Oil painting style landscape of rolling hills at golden hour, with wildflowers in the foreground, distant mountains, and dramatic clouds in the sky"
];

// Include style, subject, setting, lighting, and perspective for best results
for (const prompt of goodPrompts) {
  const imageUrl = await imageGenerator._call(prompt);
  console.log(`Generated: ${prompt.substring(0, 50)}... -> ${imageUrl}`);
}

Custom Tool Design Patterns

// Pattern 1: Stateless functional tools
const statelessTool = customTool(
  async (input: string) => {
    const params = JSON.parse(input);
    // Pure function - no side effects
    return JSON.stringify({ result: "processed", params });
  },
  { /* schema */ }
);

// Pattern 2: Tools with external service integration
const serviceTool = customTool(
  async (input: string) => {
    const { query } = JSON.parse(input);
    
    try {
      // Make external API call
      const response = await fetch(`https://api.example.com/search?q=${query}`);
      const data = await response.json();
      return JSON.stringify(data);
    } catch (error) {
      return JSON.stringify({ error: "Service unavailable" });
    }
  },
  {
    name: "external_search",
    description: "Search external API service",
    schema: z.object({ query: z.string() })
  }
);

// Pattern 3: Stateful tools with context
class ContextualTool {
  private context = new Map<string, any>();

  createTool() {
    return customTool(
      async (input: string) => {
        const { action, key, value } = JSON.parse(input);
        
        switch (action) {
          case "set":
            this.context.set(key, value);
            return JSON.stringify({ success: true, action, key });
          case "get":
            const result = this.context.get(key);
            return JSON.stringify({ value: result, key });
          case "list":
            return JSON.stringify({ keys: Array.from(this.context.keys()) });
          default:
            return JSON.stringify({ error: "Unknown action" });
        }
      },
      {
        name: "memory_tool",
        description: "Store and retrieve information in memory",
        schema: z.object({
          action: z.enum(["set", "get", "list"]),
          key: z.string().optional(),
          value: z.any().optional()
        })
      }
    );
  }
}

const contextualTool = new ContextualTool().createTool();

Error Handling and Validation

// Comprehensive error handling for tools
const robustTool = customTool(
  async (input: string) => {
    try {
      // Validate input format
      let params;
      try {
        params = JSON.parse(input);
      } catch {
        return JSON.stringify({ 
          error: "Invalid JSON input",
          code: "INVALID_INPUT" 
        });
      }

      // Validate required parameters
      const { operation, data } = params;
      if (!operation) {
        return JSON.stringify({
          error: "Missing required parameter: operation",
          code: "MISSING_PARAMETER"
        });
      }

      // Process based on operation
      switch (operation) {
        case "validate":
          // Perform validation logic
          return JSON.stringify({ 
            valid: true, 
            operation,
            timestamp: new Date().toISOString()
          });
          
        default:
          return JSON.stringify({
            error: `Unknown operation: ${operation}`,
            code: "UNKNOWN_OPERATION",
            availableOperations: ["validate"]
          });
      }
      
    } catch (error) {
      return JSON.stringify({
        error: "Internal tool error",
        code: "INTERNAL_ERROR",
        details: error instanceof Error ? error.message : "Unknown error"
      });
    }
  },
  {
    name: "robust_processor",
    description: "A robust tool with comprehensive error handling",
    schema: z.object({
      operation: z.string().describe("Operation to perform"),
      data: z.any().optional().describe("Operation data")
    })
  }
);

docs

azure-integration.md

chat-models.md

embeddings.md

index.md

language-models.md

tools.md

types-and-configuration.md

tile.json