or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

azure-integration.mdchat-models.mdembeddings.mdindex.mdlanguage-models.mdtools.mdtypes-and-configuration.md
tile.json

tools.mddocs/

0

# Tools

1

2

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

3

4

## Capabilities

5

6

### DallEAPIWrapper Class

7

8

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

9

10

```typescript { .api }

11

/**

12

* DALL-E image generation tool

13

* Creates images from text descriptions using OpenAI's DALL-E models

14

*/

15

class DallEAPIWrapper extends Tool {

16

17

constructor(fields?: Partial<DallEAPIWrapperParams>);

18

19

/** Tool identification */

20

name: string; // "dalle_image_generator"

21

description: string; // "A tool for generating images from text descriptions"

22

23

/** Model configuration */

24

model: string; // Default: "dall-e-3"

25

style: "natural" | "vivid"; // Image style (default: "vivid")

26

quality: "standard" | "hd"; // Image quality (default: "standard")

27

n: number; // Number of images to generate (default: 1)

28

size: string; // Image size (default: "1024x1024")

29

dallEResponseFormat: "url" | "b64_json"; // Response format (default: "url")

30

31

/** Client configuration */

32

openAIApiKey?: string; // OpenAI API key

33

organization?: string; // OpenAI organization ID

34

baseURL?: string; // Custom base URL

35

timeout?: number; // Request timeout

36

maxRetries?: number; // Maximum retry attempts

37

38

/** Generate image(s) from text description */

39

_call(input: string): Promise<string>;

40

41

/** Make image generation requests with retry logic */

42

imageGenerationWithRetry<T>(

43

request: OpenAIClient.Images.ImageGenerateParams,

44

options?: OpenAICallOptions

45

): Promise<T>;

46

}

47

```

48

49

### DallE Parameters Interface

50

51

Configuration interface for DALL-E API wrapper.

52

53

```typescript { .api }

54

interface DallEAPIWrapperParams {

55

/** DALL-E model version */

56

model: string;

57

58

/** Image generation style */

59

style: "natural" | "vivid";

60

61

/** Image quality level */

62

quality: "standard" | "hd";

63

64

/** Number of images to generate */

65

n: number;

66

67

/** Image dimensions */

68

size: string;

69

70

/** Response format for generated images */

71

dallEResponseFormat: "url" | "b64_json";

72

73

/** OpenAI API configuration */

74

openAIApiKey?: string;

75

organization?: string;

76

baseURL?: string;

77

timeout?: number;

78

maxRetries?: number;

79

}

80

```

81

82

### Custom Tool Creation

83

84

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

85

86

```typescript { .api }

87

/**

88

* Create custom tools for OpenAI Responses API

89

* Converts LangChain runnables into OpenAI-compatible tool definitions

90

*/

91

function customTool(

92

func: RunnableFunc<string, string, ToolRunnableConfig>,

93

fields: CustomToolFields

94

): DynamicTool<string>;

95

96

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

97

```

98

99

## Usage Examples

100

101

### Basic DALL-E Image Generation

102

103

```typescript

104

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

105

106

const dalleGenerator = new DallEAPIWrapper({

107

model: "dall-e-3",

108

apiKey: process.env.OPENAI_API_KEY,

109

quality: "hd",

110

size: "1024x1024",

111

style: "vivid"

112

});

113

114

// Generate a single image

115

const imageUrl = await dalleGenerator._call(

116

"A futuristic city skyline at sunset with flying cars and neon lights"

117

);

118

console.log("Generated image URL:", imageUrl);

119

120

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

121

```

122

123

### Different DALL-E Models and Configurations

124

125

```typescript

126

// DALL-E 3 (recommended) - high quality, single image

127

const dalleV3 = new DallEAPIWrapper({

128

model: "dall-e-3",

129

quality: "hd", // "standard" or "hd"

130

style: "natural", // "natural" or "vivid"

131

size: "1024x1792", // Portrait orientation

132

dallEResponseFormat: "url"

133

});

134

135

// DALL-E 2 - can generate multiple images

136

const dalleV2 = new DallEAPIWrapper({

137

model: "dall-e-2",

138

n: 4, // Generate 4 images (DALL-E 2 only)

139

size: "512x512", // Smaller size for DALL-E 2

140

quality: "standard" // HD not available for DALL-E 2

141

});

142

143

// Generate multiple images with DALL-E 2

144

const multipleImages = await dalleV2._call(

145

"A cute robot playing with a cat in a garden"

146

);

147

console.log("Multiple image URLs:", multipleImages);

148

```

149

150

### Supported Image Sizes

151

152

```typescript

153

// DALL-E 3 supported sizes

154

const dalle3Sizes = ["1024x1024", "1792x1024", "1024x1792"];

155

156

// DALL-E 2 supported sizes

157

const dalle2Sizes = ["256x256", "512x512", "1024x1024"];

158

159

// Create generators for different aspect ratios

160

const squareGenerator = new DallEAPIWrapper({

161

model: "dall-e-3",

162

size: "1024x1024" // Square

163

});

164

165

const landscapeGenerator = new DallEAPIWrapper({

166

model: "dall-e-3",

167

size: "1792x1024" // Landscape

168

});

169

170

const portraitGenerator = new DallEAPIWrapper({

171

model: "dall-e-3",

172

size: "1024x1792" // Portrait

173

});

174

```

175

176

### Base64 Response Format

177

178

```typescript

179

const dalle64 = new DallEAPIWrapper({

180

model: "dall-e-3",

181

dallEResponseFormat: "b64_json", // Return base64 encoded image

182

quality: "hd"

183

});

184

185

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

186

187

// Convert base64 to buffer for saving

188

const imageBuffer = Buffer.from(base64Image, 'base64');

189

190

// Save to file (Node.js)

191

import { writeFileSync } from 'fs';

192

writeFileSync('generated_image.png', imageBuffer);

193

194

// Or use in web applications

195

const dataUrl = `data:image/png;base64,${base64Image}`;

196

// dataUrl can be used directly in <img> tags

197

```

198

199

### Custom Tool Creation

200

201

```typescript

202

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

203

import { z } from "zod";

204

205

// Create a weather tool

206

const weatherTool = customTool(

207

async (input: string) => {

208

// Parse the input (it will be JSON string from the model)

209

const { location, units } = JSON.parse(input);

210

211

// Simulate weather API call

212

const temperature = Math.floor(Math.random() * 30) + 10;

213

const condition = ["sunny", "cloudy", "rainy"][Math.floor(Math.random() * 3)];

214

215

return JSON.stringify({

216

location,

217

temperature: `${temperature}°${units === 'celsius' ? 'C' : 'F'}`,

218

condition,

219

timestamp: new Date().toISOString()

220

});

221

},

222

{

223

name: "get_weather",

224

description: "Get current weather information for a specific location",

225

schema: z.object({

226

location: z.string().describe("City name or location"),

227

units: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("Temperature units")

228

})

229

}

230

);

231

232

// Create a calculator tool

233

const calculatorTool = customTool(

234

async (input: string) => {

235

const { operation, a, b } = JSON.parse(input);

236

237

let result: number;

238

switch (operation) {

239

case "add": result = a + b; break;

240

case "subtract": result = a - b; break;

241

case "multiply": result = a * b; break;

242

case "divide": result = b !== 0 ? a / b : NaN; break;

243

default: throw new Error(`Unknown operation: ${operation}`);

244

}

245

246

return JSON.stringify({ result, operation, operands: [a, b] });

247

},

248

{

249

name: "calculator",

250

description: "Perform basic mathematical operations",

251

schema: z.object({

252

operation: z.enum(["add", "subtract", "multiply", "divide"]),

253

a: z.number().describe("First number"),

254

b: z.number().describe("Second number")

255

})

256

}

257

);

258

```

259

260

### Using Custom Tools with Chat Models

261

262

```typescript

263

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

264

265

// Create chat model that supports Responses API

266

const chatModel = new ChatOpenAI({

267

model: "gpt-4o",

268

temperature: 0,

269

useResponsesApi: true // Required for custom tools

270

});

271

272

// Bind custom tools to the model

273

const modelWithCustomTools = chatModel.bindTools([

274

weatherTool,

275

calculatorTool

276

]);

277

278

// The model can now call these custom tools

279

const response = await modelWithCustomTools.invoke(

280

"What's the weather in Tokyo? Also, what's 15 multiplied by 23?"

281

);

282

283

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

284

285

// Handle tool calls if any

286

if (response.tool_calls && response.tool_calls.length > 0) {

287

for (const toolCall of response.tool_calls) {

288

console.log(`Called tool: ${toolCall.name}`);

289

console.log(`With args: ${JSON.stringify(toolCall.args)}`);

290

}

291

}

292

```

293

294

### Advanced Custom Tool Example

295

296

```typescript

297

// Database search tool with complex schema

298

const databaseSearchTool = customTool(

299

async (input: string) => {

300

const { query, filters, limit, sortBy } = JSON.parse(input);

301

302

// Simulate database search

303

const mockResults = Array.from({ length: Math.min(limit, 5) }, (_, i) => ({

304

id: i + 1,

305

title: `Result ${i + 1} for "${query}"`,

306

score: Math.random(),

307

category: filters?.category || "general",

308

timestamp: new Date(Date.now() - Math.random() * 86400000).toISOString()

309

}));

310

311

// Sort results

312

if (sortBy === "score") {

313

mockResults.sort((a, b) => b.score - a.score);

314

} else if (sortBy === "date") {

315

mockResults.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());

316

}

317

318

return JSON.stringify({

319

results: mockResults,

320

total: mockResults.length,

321

query,

322

filters

323

});

324

},

325

{

326

name: "search_database",

327

description: "Search the company database with advanced filtering and sorting",

328

schema: z.object({

329

query: z.string().describe("Search query string"),

330

filters: z.object({

331

category: z.string().optional().describe("Filter by category"),

332

dateRange: z.object({

333

start: z.string().optional().describe("Start date (ISO format)"),

334

end: z.string().optional().describe("End date (ISO format)")

335

}).optional().describe("Date range filter")

336

}).optional().describe("Search filters"),

337

limit: z.number().default(10).describe("Maximum number of results"),

338

sortBy: z.enum(["relevance", "date", "score"]).default("relevance").describe("Sort order")

339

})

340

}

341

);

342

343

// File processing tool

344

const fileProcessorTool = customTool(

345

async (input: string) => {

346

const { fileName, operation, options } = JSON.parse(input);

347

348

// Simulate file processing

349

const operations = {

350

analyze: () => ({ type: "text", lines: 150, words: 2340, size: "12KB" }),

351

compress: () => ({ originalSize: "12KB", compressedSize: "8KB", ratio: "33%" }),

352

convert: () => ({ from: "docx", to: options.format, status: "completed" })

353

};

354

355

const result = operations[operation as keyof typeof operations]?.() ||

356

{ error: "Unknown operation" };

357

358

return JSON.stringify({

359

fileName,

360

operation,

361

result,

362

timestamp: new Date().toISOString()

363

});

364

},

365

{

366

name: "process_file",

367

description: "Process files with various operations like analysis, compression, or conversion",

368

schema: z.object({

369

fileName: z.string().describe("Name of the file to process"),

370

operation: z.enum(["analyze", "compress", "convert"]).describe("Operation to perform"),

371

options: z.object({

372

format: z.string().optional().describe("Target format for conversion"),

373

quality: z.enum(["low", "medium", "high"]).optional().describe("Quality level")

374

}).optional().describe("Additional operation options")

375

})

376

}

377

);

378

```

379

380

### Error Handling with Tools

381

382

```typescript

383

// Robust tool with error handling

384

const apiTool = customTool(

385

async (input: string) => {

386

try {

387

const { endpoint, method, data } = JSON.parse(input);

388

389

// Simulate API call

390

if (endpoint === "/error") {

391

throw new Error("API endpoint not found");

392

}

393

394

return JSON.stringify({

395

status: "success",

396

endpoint,

397

method,

398

response: { message: "API call successful", data }

399

});

400

401

} catch (error) {

402

return JSON.stringify({

403

status: "error",

404

error: error instanceof Error ? error.message : "Unknown error",

405

timestamp: new Date().toISOString()

406

});

407

}

408

},

409

{

410

name: "api_call",

411

description: "Make API calls to external services",

412

schema: z.object({

413

endpoint: z.string().describe("API endpoint URL"),

414

method: z.enum(["GET", "POST", "PUT", "DELETE"]).default("GET").describe("HTTP method"),

415

data: z.record(z.any()).optional().describe("Request payload")

416

})

417

}

418

);

419

420

// Test error handling

421

const chatWithErrorHandling = new ChatOpenAI({

422

model: "gpt-4o",

423

useResponsesApi: true

424

}).bindTools([apiTool]);

425

426

const errorResponse = await chatWithErrorHandling.invoke(

427

"Make a GET request to /error endpoint"

428

);

429

```

430

431

### Combining DALL-E with Custom Tools

432

433

```typescript

434

// Create a comprehensive creative assistant

435

const imageDescriptionTool = customTool(

436

async (input: string) => {

437

const { imageUrl, analysisType } = JSON.parse(input);

438

439

// Simulate image analysis (in real app, use vision API)

440

const analyses = {

441

artistic: "This image shows vibrant colors with impressionist style brushstrokes...",

442

technical: "Resolution: 1024x1024, Color depth: 24-bit, Format: PNG...",

443

content: "The image depicts a futuristic cityscape with neon lighting..."

444

};

445

446

return JSON.stringify({

447

analysis: analyses[analysisType as keyof typeof analyses] || "General analysis not available",

448

imageUrl,

449

analysisType

450

});

451

},

452

{

453

name: "analyze_image",

454

description: "Analyze generated images for artistic, technical, or content details",

455

schema: z.object({

456

imageUrl: z.string().describe("URL of the image to analyze"),

457

analysisType: z.enum(["artistic", "technical", "content"]).describe("Type of analysis to perform")

458

})

459

}

460

);

461

462

// Creative assistant with image generation and analysis

463

const creativeAssistant = new ChatOpenAI({

464

model: "gpt-4o",

465

useResponsesApi: true

466

}).bindTools([imageDescriptionTool]);

467

468

// Also create DALL-E wrapper for image generation

469

const imageGenerator = new DallEAPIWrapper({

470

model: "dall-e-3",

471

quality: "hd",

472

style: "vivid"

473

});

474

475

// Workflow: generate image, then analyze it

476

async function createAndAnalyze(prompt: string) {

477

console.log("Generating image...");

478

const imageUrl = await imageGenerator._call(prompt);

479

480

console.log("Analyzing image...");

481

const analysis = await creativeAssistant.invoke(

482

`Analyze this generated image with artistic analysis: ${imageUrl}`

483

);

484

485

return { imageUrl, analysis: analysis.content };

486

}

487

488

const result = await createAndAnalyze(

489

"A majestic dragon soaring over a crystal castle in a fantasy landscape"

490

);

491

```

492

493

## Tool Utilities

494

495

### Built-in Tool Detection

496

497

```typescript

498

import {

499

isBuiltInTool,

500

isCustomTool,

501

parseCustomToolCall,

502

convertCompletionsCustomTool,

503

convertResponsesCustomTool

504

} from "@langchain/openai";

505

506

// Check tool types

507

const customWeatherTool = customTool(/* ... */);

508

const builtInTool = { type: "code_interpreter" };

509

510

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

511

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

512

513

// Convert between API formats

514

const completionsFormat = convertResponsesCustomTool(customWeatherTool);

515

const responsesFormat = convertCompletionsCustomTool(completionsFormat);

516

```

517

518

### Tool Conversion Utilities

519

520

```typescript

521

import {

522

formatToOpenAIFunction,

523

formatToOpenAITool,

524

formatToOpenAIAssistantTool

525

} from "@langchain/openai";

526

import { StructuredTool } from "@langchain/core/tools";

527

528

// Convert LangChain tools to OpenAI formats

529

class WeatherTool extends StructuredTool {

530

name = "get_weather";

531

description = "Get weather information";

532

533

schema = z.object({

534

location: z.string()

535

});

536

537

async _call(args: { location: string }) {

538

return `Weather in ${args.location}: Sunny, 25°C`;

539

}

540

}

541

542

const weatherTool = new WeatherTool();

543

544

// Convert to different OpenAI tool formats

545

const functionFormat = formatToOpenAIFunction(weatherTool);

546

const toolFormat = formatToOpenAITool(weatherTool);

547

const assistantFormat = formatToOpenAIAssistantTool(weatherTool);

548

549

console.log("Function format:", functionFormat);

550

console.log("Tool format:", toolFormat);

551

console.log("Assistant format:", assistantFormat);

552

```

553

554

## Best Practices

555

556

### Image Generation Guidelines

557

558

```typescript

559

// Best practices for DALL-E prompts

560

const imageGenerator = new DallEAPIWrapper({

561

model: "dall-e-3",

562

quality: "hd",

563

style: "vivid"

564

});

565

566

// Good prompt structure

567

const goodPrompts = [

568

"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",

569

570

"Vector art style illustration of a modern coffee shop interior with plants, wooden furniture, large windows showing city view, warm lighting, isometric perspective",

571

572

"Oil painting style landscape of rolling hills at golden hour, with wildflowers in the foreground, distant mountains, and dramatic clouds in the sky"

573

];

574

575

// Include style, subject, setting, lighting, and perspective for best results

576

for (const prompt of goodPrompts) {

577

const imageUrl = await imageGenerator._call(prompt);

578

console.log(`Generated: ${prompt.substring(0, 50)}... -> ${imageUrl}`);

579

}

580

```

581

582

### Custom Tool Design Patterns

583

584

```typescript

585

// Pattern 1: Stateless functional tools

586

const statelessTool = customTool(

587

async (input: string) => {

588

const params = JSON.parse(input);

589

// Pure function - no side effects

590

return JSON.stringify({ result: "processed", params });

591

},

592

{ /* schema */ }

593

);

594

595

// Pattern 2: Tools with external service integration

596

const serviceTool = customTool(

597

async (input: string) => {

598

const { query } = JSON.parse(input);

599

600

try {

601

// Make external API call

602

const response = await fetch(`https://api.example.com/search?q=${query}`);

603

const data = await response.json();

604

return JSON.stringify(data);

605

} catch (error) {

606

return JSON.stringify({ error: "Service unavailable" });

607

}

608

},

609

{

610

name: "external_search",

611

description: "Search external API service",

612

schema: z.object({ query: z.string() })

613

}

614

);

615

616

// Pattern 3: Stateful tools with context

617

class ContextualTool {

618

private context = new Map<string, any>();

619

620

createTool() {

621

return customTool(

622

async (input: string) => {

623

const { action, key, value } = JSON.parse(input);

624

625

switch (action) {

626

case "set":

627

this.context.set(key, value);

628

return JSON.stringify({ success: true, action, key });

629

case "get":

630

const result = this.context.get(key);

631

return JSON.stringify({ value: result, key });

632

case "list":

633

return JSON.stringify({ keys: Array.from(this.context.keys()) });

634

default:

635

return JSON.stringify({ error: "Unknown action" });

636

}

637

},

638

{

639

name: "memory_tool",

640

description: "Store and retrieve information in memory",

641

schema: z.object({

642

action: z.enum(["set", "get", "list"]),

643

key: z.string().optional(),

644

value: z.any().optional()

645

})

646

}

647

);

648

}

649

}

650

651

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

652

```

653

654

### Error Handling and Validation

655

656

```typescript

657

// Comprehensive error handling for tools

658

const robustTool = customTool(

659

async (input: string) => {

660

try {

661

// Validate input format

662

let params;

663

try {

664

params = JSON.parse(input);

665

} catch {

666

return JSON.stringify({

667

error: "Invalid JSON input",

668

code: "INVALID_INPUT"

669

});

670

}

671

672

// Validate required parameters

673

const { operation, data } = params;

674

if (!operation) {

675

return JSON.stringify({

676

error: "Missing required parameter: operation",

677

code: "MISSING_PARAMETER"

678

});

679

}

680

681

// Process based on operation

682

switch (operation) {

683

case "validate":

684

// Perform validation logic

685

return JSON.stringify({

686

valid: true,

687

operation,

688

timestamp: new Date().toISOString()

689

});

690

691

default:

692

return JSON.stringify({

693

error: `Unknown operation: ${operation}`,

694

code: "UNKNOWN_OPERATION",

695

availableOperations: ["validate"]

696

});

697

}

698

699

} catch (error) {

700

return JSON.stringify({

701

error: "Internal tool error",

702

code: "INTERNAL_ERROR",

703

details: error instanceof Error ? error.message : "Unknown error"

704

});

705

}

706

},

707

{

708

name: "robust_processor",

709

description: "A robust tool with comprehensive error handling",

710

schema: z.object({

711

operation: z.string().describe("Operation to perform"),

712

data: z.any().optional().describe("Operation data")

713

})

714

}

715

);

716

```