Please update app/lia_ure.py so that appointment handling behaves in two different ways: 1) DIFFERENTIATE BETWEEN SPECIFIC AND VAGUE TIMES Right now detect_appointment_confirmation() treats everything as a confirmed appointment. Change this so that we have two helpers: - is_specific_time(body_lower: str) -> bool - is_vague_time_window(body_lower: str) -> bool Use the following logic: - A message is a SPECIFIC time if it contains: - a clock pattern like "10:30", "9:00", "14:15", or - a number + am/pm (e.g. "10am", "3 pm"), or - a day word plus "at" followed by a number (e.g. "Saturday at 10", "Tuesday at 3"). - A message is a VAGUE time window if: - it contains a day word (monday–sunday, tomorrow, next week, this weekend, later today) - AND a time-of-day word like "morning", "afternoon", or "evening" - BUT does NOT contain any explicit time digits. For example: - "Can I do Tuesday afternoon?" → VAGUE - "How about Saturday at 10:30?" → SPECIFIC You can keep using DAY_WORDS, TIME_OF_DAY, RELATIVE_WORDS and TIME_REGEXES from the previous change. 2) UPDATE generate_lia_reply TO USE THESE TWO CASES BEFORE OTHER HANDLERS At the top of generate_lia_reply(), after checking opted_out, add: - If is_specific_time(body_lower) is True: - Treat this as a CONFIRMED APPOINTMENT and EARLY RETURN. - Use a confirmation message like: raw_name = customer_state.get("customer_name") name = raw_name if raw_name else "there" reply = ( f"Thanks {name} – I’ve booked you in for {inbound_text.strip()} at Lincoln Audi.\n\n" "I’ll send you a reminder beforehand and let you know who your point of contact will be when you arrive.\n\n" "If anything changes, just drop me a quick message here and I’ll be happy to move it." ) (You can improve the string slightly by stripping extra words, but using inbound_text is fine for now.) - Update state: customer_state["appointment_status"] = "BOOKED" customer_state["appointment_confirmed_text"] = inbound_text customer_state["appointment_confirmed_at"] = datetime.now(timezone.utc).isoformat() customer_state["last_message"] = inbound_text customer_state["last_reply_type"] = "APPOINTMENT_CONFIRMED" - RETURN reply, customer_state immediately so we don’t fall through to other logic. - Else if is_vague_time_window(body_lower) is True: - This means the customer has suggested a day + morning/afternoon/evening but no specific time. - Do NOT mark the appointment as booked yet. - Instead, send a reply offering two specific time options: raw_name = customer_state.get("customer_name") name = raw_name if raw_name else "there" reply = ( f"No problem, {name} – that time works.\n\n" "I’ve got two slots available: 1:00pm or 4:00pm.\n\n" "Which would suit you better?" ) - Update state: customer_state["appointment_status"] = "INVITED" # still waiting for exact time customer_state["last_message"] = inbound_text customer_state["last_reply_type"] = "APPOINTMENT_TIME_CHOICES" - RETURN reply, customer_state immediately. 3) FALLBACK APPOINTMENT DETECTION - You can keep detect_appointment_confirmation() as a wrapper that simply calls is_specific_time(). - All other logic (small talk, direct questions, tiers) should only run if neither of the above early-return cases fired. 4) NAME FALLBACK - Make sure everywhere we build the name, we use: raw_name = customer_state.get("customer_name") name = raw_name if raw_name else "there" - So we never see "Unknown" in replies. 5) Run `python -m app.lia_ure` after the changes to ensure the module still executes its test block without errors.