1010from auth .auth_utils import get_authenticated_user_details
1111
1212# Azure monitoring
13+ import re
14+ from dateutil import parser
1315from azure .monitor .opentelemetry import configure_azure_monitor
1416from config_kernel import Config
1517from event_utils import track_event_if_configured
2931 InputTask ,
3032 PlanWithSteps ,
3133 Step ,
34+ UserLanguage
3235)
3336
3437# Updated import for KernelArguments
3538from utils_kernel import initialize_runtime_and_context , rai_success
3639
40+
3741# Check if the Application Insights Instrumentation Key is set in the environment variables
3842connection_string = os .getenv ("APPLICATIONINSIGHTS_CONNECTION_STRING" )
3943if connection_string :
8185logging .info ("Added health check middleware" )
8286
8387
88+ def format_dates_in_messages (messages , target_locale = "en-US" ):
89+ """
90+ Format dates in agent messages according to the specified locale.
91+
92+ Args:
93+ messages: List of message objects or string content
94+ target_locale: Target locale for date formatting (default: en-US)
95+
96+ Returns:
97+ Formatted messages with dates converted to target locale format
98+ """
99+ # Define target format patterns per locale
100+ locale_date_formats = {
101+ "en-IN" : "%d %b %Y" , # 30 Jul 2025
102+ "en-US" : "%b %d, %Y" , # Jul 30, 2025
103+ }
104+
105+ output_format = locale_date_formats .get (target_locale , "%d %b %Y" )
106+ # Match both "Jul 30, 2025, 12:00:00 AM" and "30 Jul 2025"
107+ date_pattern = r'(\d{1,2} [A-Za-z]{3,9} \d{4}|[A-Za-z]{3,9} \d{1,2}, \d{4}(, \d{1,2}:\d{2}:\d{2} ?[APap][Mm])?)'
108+
109+ def convert_date (match ):
110+ date_str = match .group (0 )
111+ try :
112+ dt = parser .parse (date_str )
113+ return dt .strftime (output_format )
114+ except Exception :
115+ return date_str # Leave it unchanged if parsing fails
116+
117+ # Process messages
118+ if isinstance (messages , list ):
119+ formatted_messages = []
120+ for message in messages :
121+ if hasattr (message , 'content' ) and message .content :
122+ # Create a copy of the message with formatted content
123+ formatted_message = message .model_copy () if hasattr (message , 'model_copy' ) else message
124+ if hasattr (formatted_message , 'content' ):
125+ formatted_message .content = re .sub (date_pattern , convert_date , formatted_message .content )
126+ formatted_messages .append (formatted_message )
127+ else :
128+ formatted_messages .append (message )
129+ return formatted_messages
130+ elif isinstance (messages , str ):
131+ return re .sub (date_pattern , convert_date , messages )
132+ else :
133+ return messages
134+
135+
136+ @app .post ("/api/user_browser_language" )
137+ async def user_browser_language_endpoint (
138+ user_language : UserLanguage ,
139+ request : Request
140+ ):
141+ """
142+ Receive the user's browser language.
143+
144+ ---
145+ tags:
146+ - User
147+ parameters:
148+ - name: language
149+ in: query
150+ type: string
151+ required: true
152+ description: The user's browser language
153+ responses:
154+ 200:
155+ description: Language received successfully
156+ schema:
157+ type: object
158+ properties:
159+ status:
160+ type: string
161+ description: Confirmation message
162+ """
163+ config .set_user_local_browser_language (user_language .language )
164+
165+ # Log the received language for the user
166+ logging .info (f"Received browser language '{ user_language } ' for user " )
167+
168+ return {"status" : "Language received successfully" }
169+
170+
84171@app .post ("/api/input_task" )
85172async def input_task_endpoint (input_task : InputTask , request : Request ):
86173 """
87174 Receive the initial input task from the user.
88175 """
89176 # Fix 1: Properly await the async rai_success function
90- if not await rai_success (input_task .description ):
177+ if not await rai_success (input_task .description , True ):
91178 print ("RAI failed" )
92179
93180 track_event_if_configured (
@@ -177,6 +264,13 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
177264 }
178265
179266 except Exception as e :
267+ # Extract clean error message for rate limit errors
268+ error_msg = str (e )
269+ if "Rate limit is exceeded" in error_msg :
270+ match = re .search (r"Rate limit is exceeded\. Try again in (\d+) seconds?\." , error_msg )
271+ if match :
272+ error_msg = f"Rate limit is exceeded. Try again in { match .group (1 )} seconds."
273+
180274 track_event_if_configured (
181275 "InputTaskError" ,
182276 {
@@ -185,7 +279,7 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
185279 "error" : str (e ),
186280 },
187281 )
188- raise HTTPException (status_code = 400 , detail = f"Error creating plan: { e } " )
282+ raise HTTPException (status_code = 400 , detail = f"Error creating plan: { error_msg } " ) from e
189283
190284
191285@app .post ("/api/human_feedback" )
@@ -351,6 +445,18 @@ async def human_clarification_endpoint(
351445 400:
352446 description: Missing or invalid user information
353447 """
448+ if not await rai_success (human_clarification .human_clarification , False ):
449+ print ("RAI failed" )
450+ track_event_if_configured (
451+ "RAI failed" ,
452+ {
453+ "status" : "Clarification is not received" ,
454+ "description" : human_clarification .human_clarification ,
455+ "session_id" : human_clarification .session_id ,
456+ },
457+ )
458+ raise HTTPException (status_code = 400 , detail = "Invalida Clarification" )
459+
354460 authenticated_user = get_authenticated_user_details (request_headers = request .headers )
355461 user_id = authenticated_user ["user_principal_id" ]
356462 if not user_id :
@@ -626,7 +732,11 @@ async def get_plans(
626732
627733 plan_with_steps = PlanWithSteps (** plan .model_dump (), steps = steps )
628734 plan_with_steps .update_step_counts ()
629- return [plan_with_steps , messages ]
735+
736+ # Format dates in messages according to locale
737+ formatted_messages = format_dates_in_messages (messages , config .get_user_local_browser_language ())
738+
739+ return [plan_with_steps , formatted_messages ]
630740
631741 all_plans = await memory_store .get_all_plans ()
632742 # Fetch steps for all plans concurrently
0 commit comments