changes
This commit is contained in:
@@ -125,6 +125,9 @@ export async function POST(request: NextRequest) {
|
|||||||
: [...messages];
|
: [...messages];
|
||||||
let iterations = 0;
|
let iterations = 0;
|
||||||
|
|
||||||
|
// Track tool calls to detect loops (same tool with same/similar args)
|
||||||
|
const toolCallHistory: string[] = [];
|
||||||
|
|
||||||
while (iterations < MAX_TOOL_ITERATIONS) {
|
while (iterations < MAX_TOOL_ITERATIONS) {
|
||||||
iterations++;
|
iterations++;
|
||||||
|
|
||||||
@@ -203,6 +206,32 @@ export async function POST(request: NextRequest) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for duplicate/similar tool calls (sign of a loop)
|
||||||
|
// If the model is calling the same tool with the same base argument, stop
|
||||||
|
let hasDuplicateCall = false;
|
||||||
|
for (const tc of toolCalls) {
|
||||||
|
// Create a simple signature for the tool call
|
||||||
|
const mainArg = Object.values(tc.arguments)[0]?.toString().toLowerCase() || '';
|
||||||
|
const signature = `${tc.name}:${mainArg.split(',')[0].split(' ')[0]}`; // e.g., "get_weather:phoenix"
|
||||||
|
|
||||||
|
if (toolCallHistory.includes(signature)) {
|
||||||
|
hasDuplicateCall = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
toolCallHistory.push(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If duplicate detected, force a response on next iteration
|
||||||
|
if (hasDuplicateCall && iterations < MAX_TOOL_ITERATIONS - 1) {
|
||||||
|
// Skip to last iteration to force a response
|
||||||
|
iterations = MAX_TOOL_ITERATIONS - 1;
|
||||||
|
workingMessages.push({
|
||||||
|
role: 'system',
|
||||||
|
content:
|
||||||
|
'You are repeating the same tool call. Stop calling tools and provide a response using the information you already have.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Process tool calls
|
// Process tool calls
|
||||||
controller.enqueue(encoder.encode('\n\n'));
|
controller.enqueue(encoder.encode('\n\n'));
|
||||||
|
|
||||||
|
|||||||
+44
-14
@@ -11,13 +11,14 @@ export const weatherTool: Tool = {
|
|||||||
function: {
|
function: {
|
||||||
name: 'get_weather',
|
name: 'get_weather',
|
||||||
description:
|
description:
|
||||||
'Get current weather information for a location. Provides temperature, conditions, humidity, wind speed, and more.',
|
'Get current weather information for a location. Provides temperature, conditions, humidity, wind speed, and more. Use simple city names for best results (e.g., "Phoenix" not "Phoenix, AZ").',
|
||||||
parameters: {
|
parameters: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
location: {
|
location: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'City name or location (e.g., "New York", "London, UK", "Tokyo, Japan")',
|
description:
|
||||||
|
'City name, optionally with country (e.g., "New York", "London", "Tokyo, Japan"). Avoid state abbreviations like "NY" or "AZ".',
|
||||||
},
|
},
|
||||||
units: {
|
units: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -104,6 +105,43 @@ function getWindDirection(degrees: number): string {
|
|||||||
return directions[index];
|
return directions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to geocode a location, with fallback attempts for common formats
|
||||||
|
*/
|
||||||
|
async function geocodeLocation(location: string): Promise<GeocodingResult | null> {
|
||||||
|
// List of location variations to try
|
||||||
|
const variations = [
|
||||||
|
location,
|
||||||
|
// Remove state abbreviations like ", NY" or ", AZ"
|
||||||
|
location.replace(/,\s*[A-Z]{2}$/i, ''),
|
||||||
|
// Remove country/state suffixes after comma
|
||||||
|
location.split(',')[0].trim(),
|
||||||
|
// Remove "USA", "United States", etc.
|
||||||
|
location.replace(/,?\s*(USA|United States|US)$/i, '').trim(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Remove duplicates while preserving order
|
||||||
|
const uniqueVariations = Array.from(new Set(variations.map((v) => v.trim()).filter(Boolean)));
|
||||||
|
|
||||||
|
for (const query of uniqueVariations) {
|
||||||
|
try {
|
||||||
|
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(query)}&count=1&language=en&format=json`;
|
||||||
|
const geoResponse = await fetch(geoUrl, { signal: AbortSignal.timeout(10000) });
|
||||||
|
|
||||||
|
if (!geoResponse.ok) continue;
|
||||||
|
|
||||||
|
const geoData = await geoResponse.json();
|
||||||
|
if (geoData.results && geoData.results.length > 0) {
|
||||||
|
return geoData.results[0];
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Try next variation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export const weatherHandler: ToolHandler = async (args): Promise<ToolResult> => {
|
export const weatherHandler: ToolHandler = async (args): Promise<ToolResult> => {
|
||||||
const location = args.location as string;
|
const location = args.location as string;
|
||||||
const units = (args.units as 'metric' | 'imperial') || 'metric';
|
const units = (args.units as 'metric' | 'imperial') || 'metric';
|
||||||
@@ -116,24 +154,16 @@ export const weatherHandler: ToolHandler = async (args): Promise<ToolResult> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First, geocode the location
|
// Geocode the location with fallback attempts
|
||||||
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1&language=en&format=json`;
|
const geo = await geocodeLocation(location);
|
||||||
const geoResponse = await fetch(geoUrl, { signal: AbortSignal.timeout(10000) });
|
|
||||||
|
|
||||||
if (!geoResponse.ok) {
|
if (!geo) {
|
||||||
throw new Error('Failed to geocode location');
|
|
||||||
}
|
|
||||||
|
|
||||||
const geoData = await geoResponse.json();
|
|
||||||
if (!geoData.results || geoData.results.length === 0) {
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Location not found: "${location}"`,
|
error: `Location not found: "${location}". Try using just the city name (e.g., "Phoenix" instead of "Phoenix, AZ")`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const geo: GeocodingResult = geoData.results[0];
|
|
||||||
|
|
||||||
// Fetch weather data
|
// Fetch weather data
|
||||||
const tempUnit = units === 'imperial' ? 'fahrenheit' : 'celsius';
|
const tempUnit = units === 'imperial' ? 'fahrenheit' : 'celsius';
|
||||||
const windUnit = units === 'imperial' ? 'mph' : 'kmh';
|
const windUnit = units === 'imperial' ? 'mph' : 'kmh';
|
||||||
|
|||||||
Reference in New Issue
Block a user