Feature Request: Add Integration for fal.ai Image Generation

Hello LangChain Team,

I’m currently developing an agent using langgraph, and one of my key requirements is a node for dynamic image generation. I selected fal.ai for this purpose because of its vast and powerful selection of image generation models, such as FLUX.1.

Upon checking the documentation, I noticed that an official Tool for fal.ai is not yet available in the LangChain.js library.

To move forward with my project, I’ve developed a custom Tool that successfully wraps the fal.ai client. I’m sharing it here as a proof-of-concept and to propose that you consider adding official support. Given the quality and variety of models on their platform, I believe a fal.ai integration would be a valuable addition to the LangChain ecosystem for many developers.

Here is the implementation of the FalAiImageGeneration tool I created:

import { CallbackManagerForToolRun } from "@langchain/core/callbacks/manager";
import { Tool } from "@langchain/core/tools";
import { getEnvironmentVariable } from "@langchain/core/utils/env";
import { z } from "zod";
import { fal } from "@fal-ai/client";

/**
 * A Tool for generating images using the fal.ai API.
 */
export class FalAiImageGeneration extends Tool {
  static lc_name(): string {
    return "FalAiImageGeneration";
  }

  description =
    "An AI image generation tool that can generate 1-8 images in parallel from text prompts. The input must be a JSON array of strings.";

  name = "fal_ai_image_generation";

  schema = z
    .object({
      input: z
        .string()
        .optional()
        .describe("A JSON array string of prompts, supports 1-8 prompts."),
    })
    .transform((obj) => obj.input ?? "");

  protected apiKey: string;

  constructor() {
    super();
    this.apiKey = getEnvironmentVariable("FAL_API_KEY") ?? "";
    if (!this.apiKey) {
      throw new Error(
        `Fal.ai API key not found. Please set the "FAL_API_KEY" environment variable.`
      );
    }
    fal.config({
      credentials: this.apiKey,
    });
  }

  protected async _call(
    input: string,
    _runManager?: CallbackManagerForToolRun
  ): Promise<string> {
    let prompts: string[];
    try {
      prompts = JSON.parse(input);
    } catch (error) {
      return `Invalid input format. Please provide a valid JSON array string. Error: ${error}`;
    }

    if (!Array.isArray(prompts) || prompts.length === 0 || prompts.length > 8) {
      return "Input must be an array of 1 to 8 prompt strings.";
    }

    try {
      const generationPromises = prompts.map(async (prompt) => {
        try {
          const result = await fal.subscribe("fal-ai/flux/schnell", {
            input: {
              prompt: prompt, // Note: The original code had a hardcoded style prefix, removed for generality.
              image_size: "square_hd",
            },
          });
          return { success: true, prompt, result: result.data };
        } catch (error) {
          return {
            success: false,
            prompt,
            error: error instanceof Error ? error.message : "Unknown error",
          };
        }
      });

      const results = await Promise.all(generationPromises);
      return JSON.stringify(results, null, 2);
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : "An unknown error occurred";
      throw new Error(`Image generation failed: ${errorMessage}`);
    }
  }
}

/**
 * Example of how to create the tool for a ToolNode.
 */
export const TOOLS = (() => {
  try {
    return [new FalAiImageGeneration()];
  } catch (error) {
    console.warn(`Failed to initialize FalAiImageGeneration tool: ${error}`);
    return [];
  }
})();

I would be very grateful for your consideration. Please let me know if this is a direction you’d be interested in. I would be happy to help refine this code and contribute a formal pull request with proper tests and documentation.

Thank you for all your excellent work on LangChain.

1 Like