|
14 | 14 | import boto3 |
15 | 15 | from strands import tool |
16 | 16 |
|
17 | | -from ..config import create_error_response, create_response |
| 17 | +from ..config import create_error_response |
18 | 18 |
|
19 | 19 | logger = logging.getLogger(__name__) |
20 | 20 |
|
21 | 21 |
|
| 22 | +@tool |
| 23 | +def retrieve_document_context(document_id: str) -> Dict[str, Any]: |
| 24 | + """ |
| 25 | + Retrieve comprehensive document processing context via Lambda lookup function. |
| 26 | +
|
| 27 | + Invokes the lookup Lambda function to gather execution context, timing information, |
| 28 | + and Step Function details for a specific document. Provides essential data for |
| 29 | + targeted error analysis and log searching. |
| 30 | +
|
| 31 | + Use this tool to: |
| 32 | + - Get complete document processing timeline and status |
| 33 | + - Extract Lambda request IDs for CloudWatch log correlation |
| 34 | + - Identify failed functions and execution context |
| 35 | + - Obtain precise processing time windows for analysis |
| 36 | +
|
| 37 | + Alternative: If you only need basic document metadata (status, timestamps, execution ARN) |
| 38 | + without detailed execution events and Lambda request IDs, consider using fetch_document_record |
| 39 | + which provides faster access to DynamoDB tracking data. |
| 40 | +
|
| 41 | + Example usage: |
| 42 | + - "Get processing context for report.pdf" |
| 43 | + - "Retrieve execution details for lending_package.pdf" |
| 44 | + - "Show me the processing timeline for document ABC123" |
| 45 | + - "Get Lambda request IDs for failed document processing" |
| 46 | +
|
| 47 | + Args: |
| 48 | + document_id: Document ObjectKey to analyze (e.g., "report.pdf", "lending_package.pdf") |
| 49 | +
|
| 50 | + Returns: |
| 51 | + Dict containing document context, execution details, and timing information |
| 52 | + """ |
| 53 | + try: |
| 54 | + lambda_client = boto3.client("lambda") |
| 55 | + function_name = get_lookup_function_name() |
| 56 | + |
| 57 | + logger.info( |
| 58 | + f"Invoking lookup function: {function_name} for document: {document_id}" |
| 59 | + ) |
| 60 | + |
| 61 | + # Invoke lookup function |
| 62 | + response = lambda_client.invoke( |
| 63 | + FunctionName=function_name, |
| 64 | + InvocationType="RequestResponse", |
| 65 | + Payload=json.dumps({"object_key": document_id}), |
| 66 | + ) |
| 67 | + |
| 68 | + # Parse response |
| 69 | + payload = json.loads(response["Payload"].read().decode("utf-8")) |
| 70 | + |
| 71 | + if payload.get("status") == "NOT_FOUND": |
| 72 | + return create_error_response( |
| 73 | + "Document not found in tracking database", |
| 74 | + document_found=False, |
| 75 | + document_id=document_id, |
| 76 | + ) |
| 77 | + |
| 78 | + if payload.get("status") == "ERROR": |
| 79 | + return create_error_response( |
| 80 | + payload.get("message", "Unknown error from lookup function"), |
| 81 | + document_found=False, |
| 82 | + document_id=document_id, |
| 83 | + ) |
| 84 | + |
| 85 | + # Extract execution context |
| 86 | + processing_detail = payload.get("processingDetail", {}) |
| 87 | + execution_arn = processing_detail.get("executionArn") |
| 88 | + execution_events = processing_detail.get("events", []) |
| 89 | + |
| 90 | + # Extract Lambda request IDs and function mapping from execution events |
| 91 | + request_context = extract_lambda_request_ids(execution_events) |
| 92 | + request_ids = request_context.get("all_request_ids", []) |
| 93 | + function_request_map = request_context.get("function_request_map", {}) |
| 94 | + failed_functions = request_context.get("failed_functions", []) |
| 95 | + primary_failed_function = request_context.get("primary_failed_function") |
| 96 | + |
| 97 | + # Get timestamps for precise time windows |
| 98 | + timestamps = payload.get("timing", {}).get("timestamps", {}) |
| 99 | + |
| 100 | + # Calculate processing time window |
| 101 | + start_time = None |
| 102 | + end_time = None |
| 103 | + |
| 104 | + if timestamps.get("WorkflowStartTime"): |
| 105 | + start_time = datetime.fromisoformat( |
| 106 | + timestamps["WorkflowStartTime"].replace("Z", "+00:00") |
| 107 | + ) |
| 108 | + |
| 109 | + if timestamps.get("CompletionTime"): |
| 110 | + end_time = datetime.fromisoformat( |
| 111 | + timestamps["CompletionTime"].replace("Z", "+00:00") |
| 112 | + ) |
| 113 | + |
| 114 | + response = { |
| 115 | + "document_found": True, |
| 116 | + "document_id": document_id, |
| 117 | + "document_status": payload.get("status"), |
| 118 | + "execution_arn": execution_arn, |
| 119 | + "lambda_request_ids": request_ids, |
| 120 | + "function_request_map": function_request_map, |
| 121 | + "failed_functions": failed_functions, |
| 122 | + "primary_failed_function": primary_failed_function, |
| 123 | + "timestamps": timestamps, |
| 124 | + "processing_start_time": start_time, |
| 125 | + "processing_end_time": end_time, |
| 126 | + "execution_events_count": len(execution_events), |
| 127 | + "lookup_function_response": payload, |
| 128 | + } |
| 129 | + |
| 130 | + logger.info(f"Document context response for {document_id}: {response}") |
| 131 | + return response |
| 132 | + |
| 133 | + except Exception as e: |
| 134 | + logger.error(f"Error getting document context for {document_id}: {e}") |
| 135 | + return create_error_response( |
| 136 | + str(e), document_found=False, document_id=document_id |
| 137 | + ) |
| 138 | + |
| 139 | + |
22 | 140 | def get_lookup_function_name() -> str: |
23 | 141 | """ |
24 | 142 | Retrieve the Lambda lookup function name from environment configuration. |
@@ -201,104 +319,3 @@ def _extract_request_id_from_string(text: str) -> Optional[str]: |
201 | 319 | return matches[0] |
202 | 320 |
|
203 | 321 | return None |
204 | | - |
205 | | - |
206 | | -@tool |
207 | | -def lambda_lookup(document_id: str, stack_name: str = "") -> Dict[str, Any]: |
208 | | - """ |
209 | | - Retrieve comprehensive document processing context via Lambda lookup function. |
210 | | - Invokes the lookup Lambda function to gather execution context, timing information, |
211 | | - and Step Function details for a specific document. Provides essential data for |
212 | | - targeted error analysis and log searching. |
213 | | -
|
214 | | - Args: |
215 | | - document_id: Document ObjectKey to analyze |
216 | | - stack_name: CloudFormation stack name (optional, for backward compatibility) |
217 | | -
|
218 | | - Returns: |
219 | | - Dict containing document context, execution details, and timing information |
220 | | - """ |
221 | | - try: |
222 | | - lambda_client = boto3.client("lambda") |
223 | | - function_name = get_lookup_function_name() |
224 | | - |
225 | | - logger.info( |
226 | | - f"Invoking lookup function: {function_name} for document: {document_id}" |
227 | | - ) |
228 | | - |
229 | | - # Invoke lookup function |
230 | | - response = lambda_client.invoke( |
231 | | - FunctionName=function_name, |
232 | | - InvocationType="RequestResponse", |
233 | | - Payload=json.dumps({"object_key": document_id}), |
234 | | - ) |
235 | | - |
236 | | - # Parse response |
237 | | - payload = json.loads(response["Payload"].read().decode("utf-8")) |
238 | | - |
239 | | - if payload.get("status") == "NOT_FOUND": |
240 | | - return create_error_response( |
241 | | - "Document not found in tracking database", |
242 | | - document_found=False, |
243 | | - document_id=document_id, |
244 | | - ) |
245 | | - |
246 | | - if payload.get("status") == "ERROR": |
247 | | - return create_error_response( |
248 | | - payload.get("message", "Unknown error from lookup function"), |
249 | | - document_found=False, |
250 | | - document_id=document_id, |
251 | | - ) |
252 | | - |
253 | | - # Extract execution context |
254 | | - processing_detail = payload.get("processingDetail", {}) |
255 | | - execution_arn = processing_detail.get("executionArn") |
256 | | - execution_events = processing_detail.get("events", []) |
257 | | - |
258 | | - # Extract Lambda request IDs and function mapping from execution events |
259 | | - request_context = extract_lambda_request_ids(execution_events) |
260 | | - request_ids = request_context.get("all_request_ids", []) |
261 | | - function_request_map = request_context.get("function_request_map", {}) |
262 | | - failed_functions = request_context.get("failed_functions", []) |
263 | | - primary_failed_function = request_context.get("primary_failed_function") |
264 | | - |
265 | | - # Get timestamps for precise time windows |
266 | | - timestamps = payload.get("timing", {}).get("timestamps", {}) |
267 | | - |
268 | | - # Calculate processing time window |
269 | | - start_time = None |
270 | | - end_time = None |
271 | | - |
272 | | - if timestamps.get("WorkflowStartTime"): |
273 | | - start_time = datetime.fromisoformat( |
274 | | - timestamps["WorkflowStartTime"].replace("Z", "+00:00") |
275 | | - ) |
276 | | - |
277 | | - if timestamps.get("CompletionTime"): |
278 | | - end_time = datetime.fromisoformat( |
279 | | - timestamps["CompletionTime"].replace("Z", "+00:00") |
280 | | - ) |
281 | | - |
282 | | - return create_response( |
283 | | - { |
284 | | - "document_found": True, |
285 | | - "document_id": document_id, |
286 | | - "document_status": payload.get("status"), |
287 | | - "execution_arn": execution_arn, |
288 | | - "lambda_request_ids": request_ids, |
289 | | - "function_request_map": function_request_map, |
290 | | - "failed_functions": failed_functions, |
291 | | - "primary_failed_function": primary_failed_function, |
292 | | - "timestamps": timestamps, |
293 | | - "processing_start_time": start_time, |
294 | | - "processing_end_time": end_time, |
295 | | - "execution_events_count": len(execution_events), |
296 | | - "lookup_function_response": payload, |
297 | | - } |
298 | | - ) |
299 | | - |
300 | | - except Exception as e: |
301 | | - logger.error(f"Error getting document context for {document_id}: {e}") |
302 | | - return create_error_response( |
303 | | - str(e), document_found=False, document_id=document_id |
304 | | - ) |
|
0 commit comments