awslabs.cdk-mcp-server 0.0.10417__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. awslabs/__init__.py +2 -0
  2. awslabs/cdk_mcp_server/__init__.py +8 -0
  3. awslabs/cdk_mcp_server/core/__init__.py +1 -0
  4. awslabs/cdk_mcp_server/core/resources.py +271 -0
  5. awslabs/cdk_mcp_server/core/search_utils.py +182 -0
  6. awslabs/cdk_mcp_server/core/server.py +74 -0
  7. awslabs/cdk_mcp_server/core/tools.py +324 -0
  8. awslabs/cdk_mcp_server/data/__init__.py +1 -0
  9. awslabs/cdk_mcp_server/data/cdk_nag_parser.py +331 -0
  10. awslabs/cdk_mcp_server/data/construct_descriptions.py +32 -0
  11. awslabs/cdk_mcp_server/data/genai_cdk_loader.py +423 -0
  12. awslabs/cdk_mcp_server/data/lambda_powertools_loader.py +48 -0
  13. awslabs/cdk_mcp_server/data/schema_generator.py +666 -0
  14. awslabs/cdk_mcp_server/data/solutions_constructs_parser.py +782 -0
  15. awslabs/cdk_mcp_server/server.py +7 -0
  16. awslabs/cdk_mcp_server/static/CDK_GENERAL_GUIDANCE.md +232 -0
  17. awslabs/cdk_mcp_server/static/CDK_NAG_GUIDANCE.md +192 -0
  18. awslabs/cdk_mcp_server/static/__init__.py +5 -0
  19. awslabs/cdk_mcp_server/static/bedrock/agent/actiongroups.md +137 -0
  20. awslabs/cdk_mcp_server/static/bedrock/agent/alias.md +39 -0
  21. awslabs/cdk_mcp_server/static/bedrock/agent/collaboration.md +91 -0
  22. awslabs/cdk_mcp_server/static/bedrock/agent/creation.md +149 -0
  23. awslabs/cdk_mcp_server/static/bedrock/agent/custom_orchestration.md +74 -0
  24. awslabs/cdk_mcp_server/static/bedrock/agent/overview.md +78 -0
  25. awslabs/cdk_mcp_server/static/bedrock/agent/prompt_override.md +70 -0
  26. awslabs/cdk_mcp_server/static/bedrock/bedrockguardrails.md +188 -0
  27. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/chunking.md +137 -0
  28. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/datasources.md +225 -0
  29. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/kendra.md +81 -0
  30. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/overview.md +116 -0
  31. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/parsing.md +36 -0
  32. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/transformation.md +30 -0
  33. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/vector/aurora.md +185 -0
  34. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/vector/creation.md +80 -0
  35. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/vector/opensearch.md +56 -0
  36. awslabs/cdk_mcp_server/static/bedrock/knowledgebases/vector/pinecone.md +66 -0
  37. awslabs/cdk_mcp_server/static/bedrock/profiles.md +153 -0
  38. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/actiongroups.md +137 -0
  39. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/alias.md +39 -0
  40. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/collaboration.md +91 -0
  41. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/creation.md +149 -0
  42. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/custom_orchestration.md +74 -0
  43. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/overview.md +78 -0
  44. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/agent/prompt_override.md +70 -0
  45. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/bedrockguardrails.md +188 -0
  46. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/chunking.md +137 -0
  47. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/datasources.md +225 -0
  48. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/kendra.md +81 -0
  49. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/overview.md +116 -0
  50. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/parsing.md +36 -0
  51. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/transformation.md +30 -0
  52. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/vector/aurora.md +185 -0
  53. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/vector/creation.md +80 -0
  54. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/vector/opensearch.md +56 -0
  55. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/knowledgebases/vector/pinecone.md +66 -0
  56. awslabs/cdk_mcp_server/static/genai_cdk/bedrock/profiles.md +153 -0
  57. awslabs/cdk_mcp_server/static/genai_cdk/opensearch-vectorindex/overview.md +135 -0
  58. awslabs/cdk_mcp_server/static/genai_cdk/opensearchserverless/overview.md +17 -0
  59. awslabs/cdk_mcp_server/static/lambda_powertools/bedrock.md +127 -0
  60. awslabs/cdk_mcp_server/static/lambda_powertools/cdk.md +99 -0
  61. awslabs/cdk_mcp_server/static/lambda_powertools/dependencies.md +45 -0
  62. awslabs/cdk_mcp_server/static/lambda_powertools/index.md +36 -0
  63. awslabs/cdk_mcp_server/static/lambda_powertools/insights.md +95 -0
  64. awslabs/cdk_mcp_server/static/lambda_powertools/logging.md +43 -0
  65. awslabs/cdk_mcp_server/static/lambda_powertools/metrics.md +93 -0
  66. awslabs/cdk_mcp_server/static/lambda_powertools/tracing.md +63 -0
  67. awslabs/cdk_mcp_server/static/opensearch-vectorindex/overview.md +135 -0
  68. awslabs/cdk_mcp_server/static/opensearchserverless/overview.md +17 -0
  69. awslabs_cdk_mcp_server-0.0.10417.dist-info/METADATA +14 -0
  70. awslabs_cdk_mcp_server-0.0.10417.dist-info/RECORD +72 -0
  71. awslabs_cdk_mcp_server-0.0.10417.dist-info/WHEEL +4 -0
  72. awslabs_cdk_mcp_server-0.0.10417.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,666 @@
1
+ """Schema generator for Bedrock Agent Action Groups."""
2
+
3
+ import importlib.util
4
+ import json
5
+ import os
6
+ import sys
7
+ from typing import Any, Dict, List, Optional, Tuple
8
+
9
+
10
+ def generate_fallback_script(lambda_code_path: str, output_path: str) -> str:
11
+ """Generate a standalone script for schema generation."""
12
+ return f'''#!/usr/bin/env python3
13
+ """
14
+ Schema Generator for Bedrock Agent Action Groups
15
+
16
+ This script generates an OpenAPI schema from a Lambda file containing a BedrockAgentResolver app.
17
+
18
+ IMPORTANT: This script requires the following dependencies:
19
+ 1. aws-lambda-powertools
20
+ 2. pydantic
21
+
22
+ Install them with:
23
+
24
+ pip install aws-lambda-powertools pydantic
25
+
26
+ Then run this script again.
27
+
28
+ This script focuses on extracting the API definition (routes, parameters, responses)
29
+ from the BedrockAgentResolver app, NOT on executing the business logic in the Lambda function.
30
+ If you encounter errors related to missing dependencies or runtime errors in the business logic,
31
+ you can safely modify this script to bypass those errors while preserving the API definition.
32
+ """
33
+
34
+ import os
35
+ import sys
36
+ import json
37
+ import importlib.util
38
+
39
+ # Check for required dependencies
40
+ missing_deps = []
41
+ for dep in ['aws_lambda_powertools', 'pydantic']:
42
+ try:
43
+ importlib.import_module(dep)
44
+ except ImportError:
45
+ missing_deps.append(dep)
46
+
47
+ if missing_deps:
48
+ print("ERROR: Missing required dependencies: " + ", ".join(missing_deps))
49
+ print("Please install them with:")
50
+ print("pip install " + " ".join(missing_deps).replace('_', '-'))
51
+ print("Then run this script again.")
52
+ sys.exit(1)
53
+
54
+ # Configuration
55
+ LAMBDA_FILE_PATH = "{lambda_code_path}"
56
+ OUTPUT_PATH = "{output_path}"
57
+ APP_VAR_NAME = "app" # Update this if your BedrockAgentResolver instance has a different name
58
+
59
+ def main():
60
+ print(f"Generating schema from {{LAMBDA_FILE_PATH}}")
61
+ print(f"Output path: {{OUTPUT_PATH}}")
62
+
63
+ # Get the directory and module name
64
+ lambda_dir = os.path.dirname(os.path.abspath(LAMBDA_FILE_PATH))
65
+ module_name = os.path.basename(LAMBDA_FILE_PATH).replace('.py', '')
66
+
67
+ # MODIFICATION GUIDE:
68
+ # If you encounter import errors or runtime errors, you can:
69
+ # 1. Create a simplified version of the Lambda file with problematic imports/code commented out
70
+ # 2. Add try/except blocks around problematic code
71
+ # 3. Create mock implementations for missing functions
72
+ # The key is to preserve the BedrockAgentResolver app definition and routes
73
+
74
+ # Example of creating a simplified version:
75
+ simplified_path = os.path.join(lambda_dir, f"{{module_name}}_simplified.py")
76
+ try:
77
+ with open(LAMBDA_FILE_PATH, 'r') as f:
78
+ content = f.read()
79
+
80
+ # Comment out problematic imports (add more as needed)
81
+ problematic_packages = [
82
+ 'matplotlib', 'numpy', 'pandas', 'scipy', 'tensorflow', 'torch', 'sympy',
83
+ 'nltk', 'spacy', 'gensim', 'sklearn', 'networkx', 'plotly', 'dash',
84
+ 'opencv', 'cv2', 'PIL', 'pillow'
85
+ ]
86
+
87
+ lines = content.split('\\n')
88
+ for i, line in enumerate(lines):
89
+ stripped = line.strip()
90
+ if (stripped.startswith('import ') or stripped.startswith('from ')) and \
91
+ any(pkg in stripped for pkg in problematic_packages):
92
+ lines[i] = f"# {{line}} # Commented out for schema generation"
93
+
94
+ simplified_content = '\\n'.join(lines)
95
+
96
+ with open(simplified_path, 'w') as f:
97
+ f.write(simplified_content)
98
+
99
+ print("Created simplified version with problematic imports commented out")
100
+
101
+ # Try with the simplified version
102
+ try:
103
+ # Add directory to Python path
104
+ sys.path.append(os.path.dirname(simplified_path))
105
+
106
+ # Import the simplified module
107
+ print(f"Importing {{simplified_path}}...")
108
+ spec = importlib.util.spec_from_file_location(
109
+ f"{{module_name}}_simplified", simplified_path
110
+ )
111
+ module = importlib.util.module_from_spec(spec)
112
+ spec.loader.exec_module(module)
113
+
114
+ # Get the app object
115
+ if not hasattr(module, APP_VAR_NAME):
116
+ print(f"No '{{APP_VAR_NAME}}' variable found in the module.")
117
+ print("If your BedrockAgentResolver instance has a different name, update APP_VAR_NAME.")
118
+ return False
119
+
120
+ app = getattr(module, APP_VAR_NAME)
121
+
122
+ # Generate the OpenAPI schema
123
+ print("Generating OpenAPI schema...")
124
+ openapi_schema = json.loads(app.get_openapi_json_schema(openapi_version="3.0.0"))
125
+
126
+ # Fix Pydantic v2 issue (forcing OpenAPI 3.0.0)
127
+ if openapi_schema.get("openapi") != "3.0.0":
128
+ openapi_schema["openapi"] = "3.0.0"
129
+ print("Fixed OpenAPI version to 3.0.0 (Pydantic v2 issue)")
130
+
131
+ # Fix operationIds
132
+ for path in openapi_schema['paths']:
133
+ for method in openapi_schema['paths'][path]:
134
+ operation = openapi_schema['paths'][path][method]
135
+ if 'operationId' in operation:
136
+ # Get current operationId
137
+ current_id = operation['operationId']
138
+ # Remove duplication by taking the first part before '_post'
139
+ if '_post' in current_id:
140
+ # Split by underscore and remove duplicates
141
+ parts = current_id.split('_')
142
+ # Keep only unique parts and add '_post' at the end
143
+ unique_parts = []
144
+ seen = set()
145
+ for part in parts[:-1]: # Exclude the last 'post' part
146
+ if part not in seen:
147
+ unique_parts.append(part)
148
+ seen.add(part)
149
+ new_id = '_'.join(unique_parts + ['post'])
150
+ operation['operationId'] = new_id
151
+ print(f"Fixed operationId: {{current_id}} -> {{new_id}}")
152
+
153
+ # Create output directory if it doesn't exist
154
+ os.makedirs(os.path.dirname(os.path.abspath(OUTPUT_PATH)), exist_ok=True)
155
+
156
+ # Save the schema to the output path
157
+ with open(OUTPUT_PATH, 'w') as f:
158
+ json.dump(openapi_schema, f, indent=2)
159
+
160
+ print(f"Schema successfully generated and saved to {{OUTPUT_PATH}}")
161
+ return True
162
+
163
+ except Exception as simplified_error:
164
+ print(f"Error with simplified version: {{str(simplified_error)}}")
165
+ print("You may need to manually modify the script to handle this error.")
166
+ print("Focus on preserving the BedrockAgentResolver app definition and routes.")
167
+ return False
168
+
169
+ except Exception as e:
170
+ print(f"Error creating simplified version: {{str(e)}}")
171
+
172
+ # Try direct import as fallback
173
+ try:
174
+ # Add directory to Python path
175
+ sys.path.append(lambda_dir)
176
+
177
+ # Import module directly
178
+ print(f"Trying direct import of {{LAMBDA_FILE_PATH}}...")
179
+ module = __import__(module_name)
180
+
181
+ # Get the app object
182
+ if not hasattr(module, APP_VAR_NAME):
183
+ print(f"No '{{APP_VAR_NAME}}' variable found in the module.")
184
+ print("If your BedrockAgentResolver instance has a different name, update APP_VAR_NAME.")
185
+ return False
186
+
187
+ app = getattr(module, APP_VAR_NAME)
188
+
189
+ # Generate the OpenAPI schema
190
+ print("Generating OpenAPI schema...")
191
+ openapi_schema = json.loads(app.get_openapi_json_schema(openapi_version="3.0.0"))
192
+
193
+ # Fix schema issues
194
+ if openapi_schema.get("openapi") != "3.0.0":
195
+ openapi_schema["openapi"] = "3.0.0"
196
+ print("Fixed OpenAPI version to 3.0.0 (Pydantic v2 issue)")
197
+
198
+ # Create output directory if it doesn't exist
199
+ os.makedirs(os.path.dirname(os.path.abspath(OUTPUT_PATH)), exist_ok=True)
200
+
201
+ # Save the schema to the output path
202
+ with open(OUTPUT_PATH, 'w') as f:
203
+ json.dump(openapi_schema, f, indent=2)
204
+
205
+ print(f"Schema successfully generated and saved to {{OUTPUT_PATH}}")
206
+ return True
207
+
208
+ except Exception as direct_error:
209
+ print(f"Error with direct import: {{str(direct_error)}}")
210
+ print("You may need to manually modify this script to handle the errors.")
211
+ print("Remember that the goal is to extract the API definition, not to run the business logic.")
212
+ return False
213
+ finally:
214
+ # Clean up the simplified file
215
+ if os.path.exists(simplified_path):
216
+ os.remove(simplified_path)
217
+ print("Cleaned up simplified file")
218
+
219
+ if __name__ == '__main__':
220
+ main()
221
+ '''
222
+
223
+
224
+ def fix_operation_ids(openapi_schema: Dict[str, Any], result: Dict[str, Any]) -> None:
225
+ """Fix operationIds in the OpenAPI schema.
226
+
227
+ Args:
228
+ openapi_schema: The OpenAPI schema to fix
229
+ result: The result dictionary to update with warnings
230
+ """
231
+ fixed = False
232
+ for path in openapi_schema['paths']:
233
+ for method in openapi_schema['paths'][path]:
234
+ operation = openapi_schema['paths'][path][method]
235
+ if 'operationId' in operation:
236
+ # Get current operationId
237
+ current_id = operation['operationId']
238
+ # Remove duplication by taking the first part before '_post'
239
+ if '_post' in current_id:
240
+ # Split by underscore and remove duplicates
241
+ parts = current_id.split('_')
242
+ # Keep only unique parts and add '_post' at the end
243
+ unique_parts = []
244
+ seen = set()
245
+ for part in parts[:-1]: # Exclude the last 'post' part
246
+ if part not in seen:
247
+ unique_parts.append(part)
248
+ seen.add(part)
249
+ new_id = '_'.join(unique_parts + ['post'])
250
+ operation['operationId'] = new_id
251
+ fixed = True
252
+
253
+ if fixed:
254
+ result['warnings'].append('Fixed operationIds for Claude 3.5 compatibility')
255
+
256
+
257
+ def comment_out_problematic_code(
258
+ content: str, problematic_packages: List[str], import_name: Optional[str] = None
259
+ ) -> Tuple[str, List[str]]:
260
+ """Comment out problematic imports and code blocks that use them.
261
+
262
+ Args:
263
+ content: The source code content
264
+ problematic_packages: List of problematic package names
265
+ import_name: Specific import name that failed (optional)
266
+
267
+ Returns:
268
+ Tuple of (modified content, list of modifications made)
269
+ """
270
+ modifications = []
271
+
272
+ # Add the specific import that failed if not already in the list
273
+ if (
274
+ import_name
275
+ and import_name not in problematic_packages
276
+ and import_name != 'No module named'
277
+ ):
278
+ problematic_packages.append(import_name)
279
+
280
+ # Comment out problematic imports and their usage
281
+ lines = content.split('\n')
282
+ i = 0
283
+ while i < len(lines):
284
+ line = lines[i].strip()
285
+
286
+ # Check for import statements (both direct and from-imports)
287
+ if line.startswith('import ') or line.startswith('from '):
288
+ for pkg in problematic_packages:
289
+ # Match both "import pkg" and "from pkg import ..."
290
+ if (
291
+ line.startswith(f'import {pkg}')
292
+ or line.startswith(f'from {pkg} ')
293
+ or f' {pkg}' in line
294
+ or f'.{pkg}' in line
295
+ ):
296
+ lines[i] = f'# {lines[i]} # Commented out for schema generation'
297
+ modifications.append(f'Commented out import: {lines[i]}')
298
+ break
299
+
300
+ # Check for try/except blocks that might use problematic packages
301
+ if line.startswith('try:'):
302
+ # Look ahead to see if the next lines use problematic packages
303
+ j = i + 1
304
+ block_level = 1
305
+ contains_problematic_code = False
306
+
307
+ # Check the content of the try block
308
+ while j < len(lines) and block_level > 0:
309
+ next_line = lines[j].strip()
310
+ if next_line.startswith('try:'):
311
+ block_level += 1
312
+ elif next_line.startswith('except'):
313
+ block_level -= 1
314
+
315
+ # Check if this line uses any problematic package
316
+ for pkg in problematic_packages:
317
+ if pkg in lines[j]:
318
+ contains_problematic_code = True
319
+ break
320
+
321
+ j += 1
322
+
323
+ # If the try block contains problematic code, comment out the entire block
324
+ if contains_problematic_code:
325
+ lines[i] = f'# {lines[i]} # Commented out for schema generation'
326
+ modifications.append(f'Commented out try block starting at line {i + 1}')
327
+
328
+ # Comment out the entire try/except block
329
+ j = i + 1
330
+ block_level = 1
331
+ while j < len(lines) and block_level > 0:
332
+ if lines[j].strip().startswith('try:'):
333
+ block_level += 1
334
+ elif lines[j].strip().startswith('except'):
335
+ block_level -= 1
336
+
337
+ lines[j] = f'# {lines[j]} # Commented out for schema generation'
338
+ j += 1
339
+
340
+ # Skip ahead to after the block
341
+ i = j - 1
342
+
343
+ i += 1
344
+
345
+ return '\n'.join(lines), modifications
346
+
347
+
348
+ def generate_bedrock_schema_from_file(
349
+ lambda_code_path: str,
350
+ output_path: str,
351
+ ) -> Dict[str, Any]:
352
+ """Generate OpenAPI schema from a Lambda file with BedrockAgentResolver.
353
+
354
+ This function implements a progressive fallback approach:
355
+ 1. First attempt: Direct import of the Lambda file
356
+ 2. Second attempt: Create a simplified version with problematic imports commented out
357
+ 3. Last resort: Generate a fallback script for manual execution
358
+
359
+ Args:
360
+ lambda_code_path: Path to Python file containing BedrockAgentResolver app
361
+ output_path: Where to save the generated schema
362
+
363
+ Returns:
364
+ Dictionary with results of schema generation including:
365
+ - status: "success" or "error"
366
+ - schema_path: Path to the generated schema (if successful)
367
+ - warnings: List of warnings or issues detected
368
+ - process: Details about the approaches attempted
369
+ - error: Error message (if failed)
370
+ - diagnosis: Detailed diagnosis of the issue (if failed)
371
+ - solution: Suggested solution (if failed)
372
+ - fallback_script: Fallback script content (if failed)
373
+ """
374
+ result = {
375
+ 'status': 'success',
376
+ 'schema_path': output_path,
377
+ 'warnings': [],
378
+ 'process': {
379
+ 'direct_import': {'attempted': False, 'succeeded': False},
380
+ 'simplified_version': {'attempted': False, 'succeeded': False},
381
+ 'fallback_script': {'generated': False},
382
+ },
383
+ }
384
+
385
+ try:
386
+ # Check if the file exists
387
+ if not os.path.exists(lambda_code_path):
388
+ raise FileNotFoundError(f'Lambda code file not found: {lambda_code_path}')
389
+
390
+ # Get the directory and module name
391
+ lambda_dir = os.path.dirname(os.path.abspath(lambda_code_path))
392
+ module_name = os.path.basename(lambda_code_path).replace('.py', '')
393
+
394
+ # FIRST ATTEMPT: Direct import
395
+ try:
396
+ result['process']['direct_import']['attempted'] = True
397
+
398
+ # Add the directory to the Python path
399
+ sys.path.append(lambda_dir)
400
+
401
+ # Import the module
402
+ module = __import__(module_name)
403
+
404
+ # Get the app object
405
+ if not hasattr(module, 'app'):
406
+ raise AttributeError("No 'app' variable found in the module")
407
+
408
+ app = module.app
409
+
410
+ # Generate the OpenAPI schema
411
+ openapi_schema = json.loads(app.get_openapi_json_schema(openapi_version='3.0.0'))
412
+
413
+ # Fix Pydantic v2 issue (forcing OpenAPI 3.0.0)
414
+ if openapi_schema.get('openapi') != '3.0.0':
415
+ openapi_schema['openapi'] = '3.0.0'
416
+ result['warnings'].append('Fixed OpenAPI version to 3.0.0 (Pydantic v2 issue)')
417
+
418
+ # Fix operationIds
419
+ fix_operation_ids(openapi_schema, result)
420
+
421
+ # Create output directory if it doesn't exist
422
+ os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
423
+
424
+ # Save the schema to the output path
425
+ with open(output_path, 'w') as f:
426
+ json.dump(openapi_schema, f, indent=2)
427
+
428
+ result['schema'] = openapi_schema
429
+ result['process']['direct_import']['succeeded'] = True
430
+
431
+ except ImportError as e:
432
+ # SECOND ATTEMPT: Simplified version with problematic imports commented out
433
+ result['process']['direct_import']['error'] = str(e)
434
+ result['warnings'].append(f'Direct import failed: {str(e)}')
435
+
436
+ # Extract the import name that failed
437
+ import_name = str(e).split("'")[-2] if "'" in str(e) else str(e)
438
+
439
+ # Try simplified approach
440
+ result['process']['simplified_version']['attempted'] = True
441
+ simplified_path = os.path.join(lambda_dir, f'{module_name}_simplified.py')
442
+
443
+ try:
444
+ with open(lambda_code_path, 'r') as f:
445
+ content = f.read()
446
+
447
+ # Define problematic packages
448
+ problematic_packages = [
449
+ 'matplotlib',
450
+ 'numpy',
451
+ 'pandas',
452
+ 'scipy',
453
+ 'tensorflow',
454
+ 'torch',
455
+ 'sympy',
456
+ 'nltk',
457
+ 'spacy',
458
+ 'gensim',
459
+ 'sklearn',
460
+ 'networkx',
461
+ 'plotly',
462
+ 'dash',
463
+ 'opencv',
464
+ 'cv2',
465
+ 'PIL',
466
+ 'pillow',
467
+ ]
468
+
469
+ # Comment out problematic imports and code blocks
470
+ simplified_content, modifications = comment_out_problematic_code(
471
+ content, problematic_packages, import_name
472
+ )
473
+
474
+ # Add modifications to the result
475
+ result['process']['simplified_version']['modifications'] = modifications
476
+
477
+ # Write simplified file
478
+ with open(simplified_path, 'w') as f:
479
+ f.write(simplified_content)
480
+
481
+ try:
482
+ # Import simplified module
483
+ spec = importlib.util.spec_from_file_location(
484
+ f'{module_name}_simplified', simplified_path
485
+ )
486
+ if spec is None:
487
+ raise ImportError(f"Could not find spec for module: {module_name}_simplified")
488
+
489
+ simplified_module = importlib.util.module_from_spec(spec)
490
+ if spec.loader is None:
491
+ raise ImportError(f"Module spec has no loader: {module_name}_simplified")
492
+
493
+ spec.loader.exec_module(simplified_module)
494
+
495
+ # Get app and generate schema
496
+ if not hasattr(simplified_module, 'app'):
497
+ raise AttributeError("No 'app' variable found in the simplified module")
498
+
499
+ app = getattr(simplified_module, 'app')
500
+ openapi_schema = json.loads(
501
+ app.get_openapi_json_schema(openapi_version='3.0.0')
502
+ )
503
+
504
+ # Fix Pydantic v2 issue (forcing OpenAPI 3.0.0)
505
+ if openapi_schema.get('openapi') != '3.0.0':
506
+ openapi_schema['openapi'] = '3.0.0'
507
+ result['warnings'].append(
508
+ 'Fixed OpenAPI version to 3.0.0 (Pydantic v2 issue)'
509
+ )
510
+
511
+ # Fix operationIds
512
+ fix_operation_ids(openapi_schema, result)
513
+
514
+ # Create output directory if it doesn't exist
515
+ os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
516
+
517
+ # Save the schema to the output path
518
+ with open(output_path, 'w') as f:
519
+ json.dump(openapi_schema, f, indent=2)
520
+
521
+ result['schema'] = openapi_schema
522
+ result['warnings'].append(
523
+ 'Used simplified version with problematic imports and code commented out'
524
+ )
525
+ result['process']['simplified_version']['succeeded'] = True
526
+
527
+ except Exception as simplified_error:
528
+ # Both approaches failed
529
+ result['process']['simplified_version']['error'] = str(simplified_error)
530
+ result['status'] = 'error'
531
+ result['error'] = 'Both direct and simplified approaches failed'
532
+ result['original_error'] = str(e) # Preserve the original error
533
+ result['simplified_error'] = str(
534
+ simplified_error
535
+ ) # Add the simplified approach error
536
+ result['diagnosis'] = (
537
+ f'The Lambda function has dependencies that cannot be resolved: {import_name}'
538
+ )
539
+ result['solution'] = (
540
+ 'Use the fallback script and manually comment out problematic imports and code'
541
+ )
542
+
543
+ # LAST RESORT: Generate fallback script
544
+ script = generate_fallback_script(lambda_code_path, output_path)
545
+ result['fallback_script'] = script
546
+ result['process']['fallback_script']['generated'] = True
547
+
548
+ # Add instructions
549
+ result['instructions'] = (
550
+ f'Error encountered: {str(simplified_error)}\n\n'
551
+ 'To generate the schema manually, save the fallback script to a file '
552
+ 'and run it in an environment with all required dependencies installed.'
553
+ )
554
+
555
+ # Add client-agnostic instructions
556
+ result['client_instructions'] = {
557
+ 'title': 'Schema Generation Failed',
558
+ 'summary': f'The Lambda function has dependencies that cannot be resolved: {import_name}',
559
+ 'steps': [
560
+ 'Save the fallback script below to a file (e.g., generate_schema.py)',
561
+ 'Run the script in your environment where all dependencies are available',
562
+ 'The script will generate the schema at the specified output path',
563
+ ],
564
+ 'script_filename_suggestion': 'generate_schema.py',
565
+ 'command_suggestion': 'python generate_schema.py',
566
+ }
567
+
568
+ finally:
569
+ # Clean up simplified file
570
+ if os.path.exists(simplified_path):
571
+ os.remove(simplified_path)
572
+
573
+ except Exception as e:
574
+ # Error creating simplified version
575
+ result['process']['simplified_version']['error'] = str(e)
576
+ result['status'] = 'error'
577
+ result['error'] = f'Failed to create simplified version: {str(e)}'
578
+ result['diagnosis'] = (
579
+ 'Could not process the Lambda file to create a simplified version'
580
+ )
581
+ result['solution'] = (
582
+ 'Use the fallback script and manually comment out problematic imports and code'
583
+ )
584
+
585
+ # Generate fallback script
586
+ script = generate_fallback_script(lambda_code_path, output_path)
587
+ result['fallback_script'] = script
588
+ result['process']['fallback_script']['generated'] = True
589
+
590
+ # Add instructions
591
+ result['instructions'] = (
592
+ f'Error encountered: {str(e)}\n\n'
593
+ 'To generate the schema manually, save the fallback script to a file '
594
+ 'and run it in an environment with all required dependencies installed.'
595
+ )
596
+
597
+ except AttributeError as e:
598
+ # App not found
599
+ result['process']['direct_import']['error'] = str(e)
600
+ result['status'] = 'error'
601
+ result['error'] = str(e)
602
+ result['diagnosis'] = 'The BedrockAgentResolver instance was not found in the module'
603
+ result['solution'] = (
604
+ 'Edit the APP_VAR_NAME variable in the fallback script to match your BedrockAgentResolver instance name'
605
+ )
606
+
607
+ # Generate fallback script
608
+ script = generate_fallback_script(lambda_code_path, output_path)
609
+ result['fallback_script'] = script
610
+ result['process']['fallback_script']['generated'] = True
611
+
612
+ # Add instructions
613
+ result['instructions'] = (
614
+ f'Error encountered: {str(e)}\n\n'
615
+ 'To generate the schema manually, save the fallback script to a file '
616
+ 'and run it in an environment with all required dependencies installed. '
617
+ 'You may need to update the APP_VAR_NAME variable if your BedrockAgentResolver '
618
+ 'instance has a different name than "app".'
619
+ )
620
+
621
+ except Exception as e:
622
+ # Other errors
623
+ result['process']['direct_import']['error'] = str(e)
624
+ result['status'] = 'error'
625
+ result['error'] = str(e)
626
+ result['diagnosis'] = f'An unexpected error occurred: {type(e).__name__}'
627
+ result['solution'] = (
628
+ 'Use the fallback script and check for syntax errors or other issues in your Lambda function'
629
+ )
630
+
631
+ # Generate fallback script
632
+ script = generate_fallback_script(lambda_code_path, output_path)
633
+ result['fallback_script'] = script
634
+ result['process']['fallback_script']['generated'] = True
635
+
636
+ # Add instructions
637
+ result['instructions'] = (
638
+ f'Error encountered: {str(e)}\n\n'
639
+ 'To generate the schema manually, save the fallback script to a file '
640
+ 'and run it in an environment with all required dependencies installed.'
641
+ )
642
+
643
+ finally:
644
+ # Clean up sys.path
645
+ if lambda_dir in sys.path:
646
+ sys.path.remove(lambda_dir)
647
+
648
+ except Exception as e:
649
+ result['status'] = 'error'
650
+ result['error'] = str(e)
651
+ result['diagnosis'] = f'Error accessing or processing the Lambda file: {type(e).__name__}'
652
+ result['solution'] = 'Check file permissions and path correctness'
653
+
654
+ # Generate fallback script
655
+ script = generate_fallback_script(lambda_code_path, output_path)
656
+ result['fallback_script'] = script
657
+ result['process']['fallback_script']['generated'] = True
658
+
659
+ # Add instructions
660
+ result['instructions'] = (
661
+ f'Error encountered: {str(e)}\n\n'
662
+ 'To generate the schema manually, save the fallback script to a file '
663
+ 'and run it in an environment with all required dependencies installed.'
664
+ )
665
+
666
+ return result