refactor: move schema updates to executor
- Executor now updates TPM.js database directly when loading tools - Update /api/tools/update-schema to use packageName+exportName lookup - Remove schema update logic from HLLM proxy (no longer needed)
This commit is contained in:
parent
3f54f16573
commit
feeb3cf3e8
2 changed files with 110 additions and 18 deletions
|
|
@ -48,6 +48,45 @@ async function reportToolHealth(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tool schema in TPM.js database
|
||||
* Non-blocking - fires and forgets to keep schemas up to date
|
||||
*/
|
||||
async function updateToolSchema(
|
||||
packageName: string,
|
||||
exportName: string,
|
||||
description: string,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: JSON Schema can have any structure
|
||||
inputSchema: any
|
||||
): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${TPMJS_API_URL}/api/tools/update-schema`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
packageName,
|
||||
exportName,
|
||||
description,
|
||||
inputSchema,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log(
|
||||
`📋 Schema updated for ${packageName}/${exportName}:`,
|
||||
data.updated ? 'UPDATED' : 'NO CHANGE'
|
||||
);
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.warn(`⚠️ Failed to update schema: ${response.status}`, errorText);
|
||||
}
|
||||
} catch (err) {
|
||||
// Non-blocking - just log
|
||||
console.error('❌ Failed to update tool schema:', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize JSON Schema to fix common issues
|
||||
* - Replaces invalid type "None" with "object"
|
||||
|
|
@ -354,6 +393,13 @@ async function loadAndDescribe(req: Request): Promise<Response> {
|
|||
// Sanitize schema - fix common issues with invalid schemas
|
||||
const sanitizedSchema = sanitizeJsonSchema(rawJsonSchema);
|
||||
|
||||
// Update TPM.js database with the schema (async, non-blocking)
|
||||
updateToolSchema(packageName, exportName, toolModule.description, sanitizedSchema).catch(
|
||||
(err) => {
|
||||
console.warn('⚠️ Failed to update schema in database:', err);
|
||||
}
|
||||
);
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
tool: {
|
||||
|
|
|
|||
|
|
@ -8,21 +8,25 @@ export const dynamic = 'force-dynamic';
|
|||
* POST /api/tools/update-schema
|
||||
* Update a tool's input schema (parameters field)
|
||||
*
|
||||
* This is called when a tool is executed and we discover its actual schema
|
||||
* from the executor's /load-and-describe endpoint.
|
||||
* Called by the executor when it loads a tool and discovers its schema.
|
||||
* Looks up tool by packageName + exportName (unique constraint).
|
||||
*
|
||||
* Body:
|
||||
* - toolId: The tool's database ID
|
||||
* - packageName: npm package name
|
||||
* - exportName: exported function name
|
||||
* - inputSchema: The JSON Schema for the tool's input parameters
|
||||
* - description: Optional updated description from the tool
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { toolId, inputSchema, description } = body;
|
||||
const { packageName, exportName, inputSchema, description } = body;
|
||||
|
||||
if (!toolId) {
|
||||
return NextResponse.json({ success: false, error: 'toolId is required' }, { status: 400 });
|
||||
if (!packageName || !exportName) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'packageName and exportName are required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!inputSchema) {
|
||||
|
|
@ -32,12 +36,37 @@ export async function POST(request: NextRequest) {
|
|||
);
|
||||
}
|
||||
|
||||
console.log('[Update Schema] Updating tool:', toolId);
|
||||
console.log('[Update Schema] Schema properties:', Object.keys(inputSchema.properties || {}));
|
||||
console.log('[Update Schema] Looking up tool:', { packageName, exportName });
|
||||
|
||||
// Find the tool by package name and export name
|
||||
const tool = await prisma.tool.findFirst({
|
||||
where: {
|
||||
exportName,
|
||||
package: {
|
||||
npmPackageName: packageName,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
parameters: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!tool) {
|
||||
console.log('[Update Schema] Tool not found:', { packageName, exportName });
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Tool not found', updated: false },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
// Convert JSON Schema to our parameters format
|
||||
// The parameters field stores an array of parameter objects
|
||||
const parameters = [];
|
||||
const parameters: Array<{
|
||||
name: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
description: string;
|
||||
}> = [];
|
||||
if (inputSchema.properties) {
|
||||
for (const [name, prop] of Object.entries(inputSchema.properties)) {
|
||||
const propDef = prop as { type?: string; description?: string };
|
||||
|
|
@ -50,18 +79,38 @@ export async function POST(request: NextRequest) {
|
|||
}
|
||||
}
|
||||
|
||||
// Update the tool in the database
|
||||
// Check if parameters already match (avoid unnecessary updates)
|
||||
const existingParams = tool.parameters as Array<{ name: string }> | null;
|
||||
const existingParamNames =
|
||||
existingParams
|
||||
?.map((p) => p.name)
|
||||
.sort()
|
||||
.join(',') || '';
|
||||
const newParamNames = parameters
|
||||
.map((p) => p.name)
|
||||
.sort()
|
||||
.join(',');
|
||||
|
||||
if (existingParamNames === newParamNames && parameters.length > 0) {
|
||||
console.log('[Update Schema] Schema already up to date:', { packageName, exportName });
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
updated: false,
|
||||
message: 'Schema already up to date',
|
||||
});
|
||||
}
|
||||
|
||||
// Update the tool
|
||||
const updateData: { parameters: typeof parameters; description?: string } = {
|
||||
parameters,
|
||||
};
|
||||
|
||||
// Only update description if provided and different
|
||||
if (description) {
|
||||
updateData.description = description;
|
||||
}
|
||||
|
||||
const updatedTool = await prisma.tool.update({
|
||||
where: { id: toolId },
|
||||
where: { id: tool.id },
|
||||
data: updateData,
|
||||
select: {
|
||||
id: true,
|
||||
|
|
@ -75,20 +124,17 @@ export async function POST(request: NextRequest) {
|
|||
id: updatedTool.id,
|
||||
exportName: updatedTool.exportName,
|
||||
parameterCount: parameters.length,
|
||||
parameterNames: parameters.map((p) => p.name),
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
updated: true,
|
||||
tool: updatedTool,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[Update Schema] Error:', error);
|
||||
|
||||
// Handle not found error
|
||||
if (error instanceof Error && error.message.includes('Record to update not found')) {
|
||||
return NextResponse.json({ success: false, error: 'Tool not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue