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.