diff --git a/skyvern/forge/prompts/skyvern/check-date-format.j2 b/skyvern/forge/prompts/skyvern/check-date-format.j2 new file mode 100644 index 00000000..8bcb664c --- /dev/null +++ b/skyvern/forge/prompts/skyvern/check-date-format.j2 @@ -0,0 +1,31 @@ +Your goal is to check whether the format of the date matches the required format 'YYYY-MM-DD' based on the user's goals, user details. + +MAKE SURE YOU OUTPUT VALID JSON. No text before or after JSON, no trailing commas, no comments (//), no unnecessary quotes, etc. + +Reply in JSON format with the following keys: +{ +"page_info": str, // Think step by step. Describe all the useful information in the page related to the user goal. +"thought": str, // Think step by step. Describe your thought about how you come up the result. Use information you see on the site to explain. +"is_current_format_correct": bool, // True if the current date format is matching the required format 'YYYY-MM-DD'. +"recommended_date": str, // If is_current_format_correct is True, return null. Otherwise, return the recommended date with the correct format 'YYYY-MM-DD'. +} + +Current value: +``` +{{ current_value }} +``` + +User goal: +``` +{{ navigation_goal }} +``` + +User details: +``` +{{ navigation_payload_str }} +``` + +Current datetime, ISO format: +``` +{{ local_datetime }} +``` \ No newline at end of file diff --git a/skyvern/utils/prompt_engine.py b/skyvern/utils/prompt_engine.py index 48b1cee7..1af0e1f5 100644 --- a/skyvern/utils/prompt_engine.py +++ b/skyvern/utils/prompt_engine.py @@ -20,6 +20,13 @@ class CheckPhoneNumberFormatResponse(BaseModel): recommended_phone_number: str | None +class CheckDateFormatResponse(BaseModel): + page_info: str + thought: str + is_current_format_correct: bool + recommended_date: str | None + + HTMLTreeStr = str diff --git a/skyvern/webeye/actions/handler.py b/skyvern/webeye/actions/handler.py index 2cec67d1..119e48c6 100644 --- a/skyvern/webeye/actions/handler.py +++ b/skyvern/webeye/actions/handler.py @@ -73,7 +73,11 @@ from skyvern.forge.sdk.services.bitwarden import BitwardenConstants from skyvern.forge.sdk.services.credentials import OnePasswordConstants from skyvern.forge.sdk.trace import TraceManager from skyvern.services.task_v1_service import is_cua_task -from skyvern.utils.prompt_engine import CheckPhoneNumberFormatResponse, load_prompt_with_elements +from skyvern.utils.prompt_engine import ( + CheckDateFormatResponse, + CheckPhoneNumberFormatResponse, + load_prompt_with_elements, +) from skyvern.webeye.actions import actions, handler_utils from skyvern.webeye.actions.action_types import ActionType from skyvern.webeye.actions.actions import ( @@ -295,6 +299,43 @@ async def check_phone_number_format( return check_phone_number_format_response.recommended_phone_number +async def check_date_format( + value: str, + action: actions.InputTextAction, + skyvern_element: SkyvernElement, + task: Task, + step: Step, +) -> str: + # check the date format + LOG.info( + "Input is a date input, trigger date format checking", + action=action, + element_id=skyvern_element.get_id(), + ) + + prompt = prompt_engine.load_prompt( + template="check-date-format", + current_value=value, + navigation_goal=task.navigation_goal, + navigation_payload_str=json.dumps(task.navigation_payload), + local_datetime=datetime.now(skyvern_context.ensure_context().tz_info).isoformat(), + ) + + json_response = await app.SECONDARY_LLM_API_HANDLER(prompt=prompt, step=step, prompt_name="check-date-format") + + check_date_format_response = CheckDateFormatResponse.model_validate(json_response) + if check_date_format_response.is_current_format_correct or not check_date_format_response.recommended_date: + return value + + LOG.info( + "The current date format is incorrect, using the recommended date", + action=action, + element_id=skyvern_element.get_id(), + recommended_date=check_date_format_response.recommended_date, + ) + return check_date_format_response.recommended_date + + class AutoCompletionResult(BaseModel): auto_completion_attempt: bool = False incremental_elements: list[dict] = [] @@ -1148,6 +1189,17 @@ async def handle_input_text_action( if len(text) == 0: return [ActionSuccess()] + if tag_name == InteractiveElement.INPUT and await skyvern_element.get_attr("type") == "date": + text = await check_date_format( + value=text, + action=action, + skyvern_element=skyvern_element, + task=task, + step=step, + ) + await skyvern_element.input_fill(text=text) + return [ActionSuccess()] + if not await skyvern_element.is_raw_input(): if await skyvern_element.is_auto_completion_input() or input_or_select_context.is_location_input: if result := await input_or_auto_complete_input(