Hey guys, I need help…I am building a custom tool, and I am getting this error:
Type instantiation is excessively deep and possibly infinite.
On typescript… someone already passed by that?
This is the file:
import { StructuredTool } from '@langchain/core/tools';
import { z } from 'zod';
import { EntityManager } from '@mikro-orm/core';
import { SalesTransaction, TransactionStatus } from '../../../../sales/entities/sales-transaction.entity';
import { Logger } from '@nestjs/common';
// Define the input schema
export const CalculateRevenueSchema = z.object({
startDate: z.string().describe('Start date in YYYY-MM-DD format'),
endDate: z.string().describe('End date in YYYY-MM-DD format'),
unitId: z.string().describe('Unit ID to calculate revenue for'),
});
export type CalculateRevenueInput = z.infer<typeof CalculateRevenueSchema>;
// Define the output schema for better type safety
export const CalculateRevenueOutputSchema = z.object({
success: z.boolean(),
data: z.object({
revenue: z.number(),
period: z.object({
start: z.string(),
end: z.string(),
}),
unitId: z.string(),
transactionsCount: z.number(),
formattedRevenue: z.string(),
}),
performance: z.object({
executionTime: z.number(),
queryTime: z.number(),
toolId: z.string(),
}),
});
export type CalculateRevenueOutput = z.infer<typeof CalculateRevenueOutputSchema>;
/**
* Tool for calculating total revenue for a specific date range and unit
* Refactored to use StructuredTool for proper schema handling
*/
export class CalculateRevenueTool extends StructuredTool<
typeof CalculateRevenueSchema,
CalculateRevenueInput,
CalculateRevenueOutput
> {
name = 'calculate_revenue';
description = 'Calculate total revenue for a specific date range and business unit';
schema = CalculateRevenueSchema; // This is the key difference!
private readonly logger = new Logger(CalculateRevenueTool.name);
constructor(private em: EntityManager) {
super();
this.logger.debug('🔧 CalculateRevenueTool initialized');
}
// Note: _call now receives structured input directly, not a string!
protected async _call(input: CalculateRevenueInput): Promise<CalculateRevenueOutput> {
const startTime = Date.now();
const toolId = `cr-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
this.logger.debug(`[🔧 ${toolId}] Starting revenue calculation`, {
input,
timestamp: new Date().toISOString(),
});
try {
const { startDate, endDate, unitId } = input;
// Validate date format
const startDateObj = new Date(startDate);
const endDateObj = new Date(endDate);
if (isNaN(startDateObj.getTime()) || isNaN(endDateObj.getTime())) {
throw new Error('Invalid date format. Use YYYY-MM-DD');
}
if (startDateObj > endDateObj) {
throw new Error('Start date must be before end date');
}
// Calculate revenue
this.logger.debug(`[🔧 ${toolId}] Querying transactions`, {
unitId,
dateRange: {
start: startDateObj.toISOString(),
end: endDateObj.toISOString(),
},
status: TransactionStatus.PAID,
});
const queryStartTime = Date.now();
const transactions = await this.em.find(SalesTransaction, {
unit: unitId,
transactionDate: {
$gte: startDateObj,
$lte: endDateObj,
},
status: TransactionStatus.PAID,
});
const queryTime = Date.now() - queryStartTime;
const revenue = transactions.reduce((sum, t) => sum + Number(t.total), 0);
this.logger.debug(`[🔧 ${toolId}] Revenue calculation completed`, {
transactionsFound: transactions.length,
totalRevenue: revenue,
queryTime,
unitId,
});
const executionTime = Date.now() - startTime;
this.logger.log(`[🔧 ${toolId}] ✅ Revenue calculated successfully`, {
unitId,
revenue,
transactionsCount: transactions.length,
period: { start: startDate, end: endDate },
executionTime,
queryTime,
timestamp: new Date().toISOString(),
});
// Return structured data directly (not JSON string!)
return {
success: true,
data: {
revenue,
period: { start: startDate, end: endDate },
unitId,
transactionsCount: transactions.length,
formattedRevenue: new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL',
}).format(revenue),
},
performance: {
executionTime,
queryTime,
toolId,
},
};
} catch (error) {
const executionTime = Date.now() - startTime;
const errorMessage = error instanceof Error ? error.message : String(error);
this.logger.error(`[🔧 ${toolId}] ❌ Revenue calculation failed`, {
error: errorMessage,
stack: error instanceof Error ? error.stack : undefined,
executionTime,
input,
timestamp: new Date().toISOString(),
});
// Return error in structured format
return {
success: false,
data: {
revenue: 0,
period: { start: input.startDate, end: input.endDate },
unitId: input.unitId,
transactionsCount: 0,
formattedRevenue: 'R$ 0,00',
},
performance: {
executionTime,
queryTime: 0,
toolId,
},
};
}
}
}
i need create the custom schema because if i didn’t do that the agent don’t know what to pass to this tool
I am using the createSupervisor and createReactAgents…
and my project is typescript