E2E lambda deployment using agent without tool calls

This commit is contained in:
Siddharth Ganesan
2025-07-07 16:21:00 -07:00
parent d0514a39a8
commit a6e144ad93
4 changed files with 63 additions and 75 deletions

View File

@@ -202,18 +202,13 @@ export async function POST(request: NextRequest) {
}
}
// Parse the runtime field if it's a JSON string
if (typeof body.runtime === 'string') {
try {
body.runtime = JSON.parse(body.runtime)
logger.info(`[${requestId}] Parsed runtime field:`, { parsedRuntime: body.runtime })
} catch (parseError) {
logger.error(`[${requestId}] Failed to parse runtime field as JSON`, {
error: parseError instanceof Error ? parseError.message : String(parseError),
runtimeString: body.runtime,
})
return createErrorResponse('Invalid JSON in runtime field', 400, 'INVALID_RUNTIME_JSON')
}
// Runtime field should be a string, no JSON parsing needed
if (typeof body.runtime !== 'string') {
logger.error(`[${requestId}] Runtime field must be a string`, {
runtimeType: typeof body.runtime,
runtimeValue: body.runtime,
})
return createErrorResponse('Runtime field must be a string', 400, 'INVALID_RUNTIME_TYPE')
}
// Parse the timeout field if it's a JSON string

View File

@@ -22,44 +22,44 @@ Your output should be a valid JSON object, with the following structure:
]`
const schema = {
"name": "aws_lambda_function",
"description": "Defines the structure for an AWS Lambda function configuration.",
"strict": true,
"schema": {
"type": "object",
"properties": {
"runtime": {
"type": "string",
"description": "The runtime environment for the Lambda function."
name: 'aws_lambda_function',
description: 'Defines the structure for an AWS Lambda function configuration.',
strict: true,
schema: {
type: 'object',
properties: {
runtime: {
type: 'string',
description: 'The runtime environment for the Lambda function.',
},
"handler": {
"type": "string",
"description": "The function handler that Lambda calls to start execution."
handler: {
type: 'string',
description: 'The function handler that Lambda calls to start execution.',
},
"memory": {
"type": "integer",
"description": "The amount of memory allocated to the Lambda function in MB (128-10240).",
"minimum": 128,
"maximum": 10240
memory: {
type: 'integer',
description: 'The amount of memory allocated to the Lambda function in MB (128-10240).',
minimum: 128,
maximum: 10240,
},
"timeout": {
"type": "integer",
"description": "The maximum execution time for the Lambda function in seconds (1-900).",
"minimum": 1,
"maximum": 900
timeout: {
type: 'integer',
description: 'The maximum execution time for the Lambda function in seconds (1-900).',
minimum: 1,
maximum: 900,
},
files: {
type: 'object',
description: 'A mapping of file paths to their respective code strings.',
additionalProperties: {
type: 'string',
description: 'The code string for a specific file.',
},
},
"files": {
"type": "object",
"description": "A mapping of file paths to their respective code strings.",
"additionalProperties": {
"type": "string",
"description": "The code string for a specific file."
}
}
},
"additionalProperties": false,
"required": ["runtime", "handler", "files", "memory", "timeout"]
}
additionalProperties: false,
required: ['runtime', 'handler', 'files', 'memory', 'timeout'],
},
}
export async function POST(request: NextRequest) {
@@ -86,10 +86,6 @@ export async function POST(request: NextRequest) {
stack: error instanceof Error ? error.stack : undefined,
})
return createErrorResponse(
'Failed to get prompts and schema',
500,
'GET_PROMPTS_ERROR'
)
return createErrorResponse('Failed to get prompts and schema', 500, 'GET_PROMPTS_ERROR')
}
}
}

View File

@@ -2,8 +2,6 @@ import { S3Icon } from '@/components/icons'
import type { ToolResponse } from '@/tools/types'
import type { BlockConfig } from '../types'
// Define the expected response type for AWS Lambda operations
interface AWSLambdaResponse extends ToolResponse {
output: {
@@ -63,7 +61,7 @@ export const AWSLambdaBlock: BlockConfig<AWSLambdaResponse> = {
id: 'region',
title: 'AWS Region',
type: 'dropdown',
layout: 'half',
layout: 'full',
options: [
'us-east-1',
'us-east-2',
@@ -101,7 +99,7 @@ export const AWSLambdaBlock: BlockConfig<AWSLambdaResponse> = {
password: false,
condition: {
field: 'operation',
value: ['create/update'],
value: ['fetch', 'create/update'],
},
},
{
@@ -155,7 +153,7 @@ export const AWSLambdaBlock: BlockConfig<AWSLambdaResponse> = {
layout: 'full',
language: 'json',
placeholder:
'{\n "index.js": "exports.handler = async (event) => {\n return {\n statusCode: 200,\n body: JSON.stringify({\n message: \"Hello from Lambda!\"\n })\n };\n };"\n}',
'{\n "index.js": "exports.handler = async (event) => {...};"\n}',
condition: {
field: 'operation',
value: ['create/update'],
@@ -213,15 +211,15 @@ export const AWSLambdaBlock: BlockConfig<AWSLambdaResponse> = {
access: ['aws_lambda_deploy', 'aws_lambda_fetch', 'aws_lambda_get_prompts'],
config: {
tool: (params: Record<string, any>) => {
const operation = String(params.operation || '').trim();
const operation = String(params.operation || '').trim()
// Only map user-facing names; pass through tool IDs as-is
const operationMap: Record<string, string> = {
'fetch': 'aws_lambda_fetch',
fetch: 'aws_lambda_fetch',
'create/update': 'aws_lambda_deploy',
'getPrompts': 'aws_lambda_get_prompts',
};
getPrompts: 'aws_lambda_get_prompts',
}
if (operationMap[operation]) {
return operationMap[operation];
return operationMap[operation]
}
// If already a tool ID, return as-is
if (
@@ -229,19 +227,19 @@ export const AWSLambdaBlock: BlockConfig<AWSLambdaResponse> = {
operation === 'aws_lambda_deploy' ||
operation === 'aws_lambda_get_prompts'
) {
return operation;
return operation
}
// Default fallback
console.warn(`Unknown operation: "${operation}", defaulting to aws_lambda_fetch`);
return 'aws_lambda_fetch';
console.warn(`Unknown operation: "${operation}", defaulting to aws_lambda_fetch`)
return 'aws_lambda_fetch'
},
},
},
inputs: {
accessKeyId: { type: 'string', required: false },
secretAccessKey: { type: 'string', required: false },
region: { type: 'string', required: false },
role: { type: 'string', required: false },
accessKeyId: { type: 'string', required: true },
secretAccessKey: { type: 'string', required: true },
region: { type: 'string', required: true },
role: { type: 'string', required: true },
operation: { type: 'string', required: true },
functionName: { type: 'string', required: false },
handler: { type: 'string', required: false },

View File

@@ -1,17 +1,16 @@
import type { ToolConfig } from '../types'
interface AWSLambdaGetPromptsParams {
// No parameters needed for this operation
}
type AWSLambdaGetPromptsParams = {}
interface AWSLambdaGetPromptsResponse {
systemPrompt: string
schema: Record<string, any>
}
export const awsLambdaGetPromptsTool: ToolConfig<AWSLambdaGetPromptsParams, AWSLambdaGetPromptsResponse> = {
export const awsLambdaGetPromptsTool: ToolConfig<
AWSLambdaGetPromptsParams,
AWSLambdaGetPromptsResponse
> = {
id: 'aws_lambda_get_prompts',
name: 'AWS Lambda Get Prompts',
description: 'Get system prompt and schema for AWS Lambda operations',
@@ -29,4 +28,4 @@ export const awsLambdaGetPromptsTool: ToolConfig<AWSLambdaGetPromptsParams, AWSL
}),
body: () => ({}), // No body needed
},
}
}