-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlambda_handler.py
More file actions
116 lines (97 loc) · 3.95 KB
/
Copy pathlambda_handler.py
File metadata and controls
116 lines (97 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import json
import os
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
if not os.getenv("OPENAI_API_KEY"):
raise RuntimeError(
"OPENAI_API_KEY is not set. Configure it as a Lambda environment variable or in .env for local testing."
)
from src.graph import build_graph
from src.state import NOCAgentState
CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
"Content-Type": "application/json",
}
def lambda_handler(event: dict, context) -> dict:
"""
AWS Lambda handler for the Telecom NOC Resolution Agent.
Accepts both API Gateway events (with a JSON body string) and direct Lambda
invocation events (flat dict with alarm_id key).
Args:
event: Lambda/API Gateway event dict.
context: Lambda context object (unused; may be None for local testing).
Returns:
API Gateway-compatible response dict with statusCode, headers, and JSON body.
"""
start_time = datetime.now()
# ── Parse request body ────────────────────────────────────────────────────
if "body" in event:
# API Gateway event — body is a JSON string
try:
body = json.loads(event.get("body") or "{}")
except (json.JSONDecodeError, TypeError):
return {
"statusCode": 400,
"headers": CORS_HEADERS,
"body": json.dumps({"error": "Request body is not valid JSON"}),
}
else:
# Direct Lambda invocation (local testing / main.py compat)
body = event
# ── Validate required fields ──────────────────────────────────────────────
alarm_id = body.get("alarm_id")
if not alarm_id:
return {
"statusCode": 400,
"headers": CORS_HEADERS,
"body": json.dumps({"error": "alarm_id is required"}),
}
error_message = body.get("error_message", "")
print(f"[Lambda] Received alarm: {alarm_id}")
# ── Build graph and invoke ────────────────────────────────────────────────
initial_state: NOCAgentState = {
"alarm_id": alarm_id,
"error_message": error_message,
"telemetry": {},
"sops": [],
"resolution_ticket": "",
"is_safe": None,
"safety_feedback": None,
"iterations": 0,
}
graph = build_graph()
try:
final_state = graph.invoke(initial_state)
except Exception as e:
print(f"[Lambda] ERROR during graph execution: {e}")
return {
"statusCode": 500,
"headers": CORS_HEADERS,
"body": json.dumps({"error": str(e), "alarm_id": alarm_id}),
}
elapsed = (datetime.now() - start_time).total_seconds()
print(
f"[Lambda] Workflow completed in {elapsed:.2f}s | "
f"safe={final_state.get('is_safe')} | "
f"iterations={final_state.get('iterations', 0)}"
)
return {
"statusCode": 200,
"headers": CORS_HEADERS,
"body": json.dumps(
{
"alarm_id": final_state.get("alarm_id"),
"is_safe": final_state.get("is_safe"),
"safety_feedback": final_state.get("safety_feedback"),
"resolution_ticket": final_state.get("resolution_ticket"),
"iterations": final_state.get("iterations", 0),
"elapsed_seconds": round(elapsed, 2),
}
),
}
# ---------------------------------------------------------------------------
# Backward-compat alias — the original handler name used by direct Lambda tests
# ---------------------------------------------------------------------------
handler = lambda_handler