Task: workarena.servicenow.order-standard-laptop
Goal: Go to the Service Catalog hardware store and order 5 "Standard Laptop" with configuration {'Additional software requirements': 'Slack, Trello, Zoom, Microsoft Office 365, Asana, HubSpot', 'Adobe Acrobat': True, 'Adobe Photoshop': False}
Task configuration: {'configuration': {'Additional software requirements': ['textarea', 'Slack, Trello, Zoom, Microsoft Office 365, Asana, HubSpot'], 'Adobe Acrobat': ['checkbox', True], 'Adobe Photoshop': ['checkbox', False]}, 'description': 'Lenovo - Carbon x1', 'item': 'Standard Laptop', 'quantity': 5}

Validation code:
import json
import os
import re
import urllib.parse as parse
from typing import Any, Dict, List, Optional

import requests


def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:
    """
    Validate a submitted request based on the last URL and a request record in `config`.

    Required in `config`:
      - requests: Dict[str, Dict]   # sys_id -> request dict with shape:
        {
          "items": [
            {
              "short_description": str,
              "quantity": str|int,
              "options": Dict[str, Any]
            }
          ]
        }
      - short_description: str       # expected
      - quantity: int|str            # expected
      - requested_configuration: Dict[str, Tuple[str, Any]]  # key -> (element_type, value)
        # element_type in {"checkbox","radio","textarea"}

    Optional in `config`:
      - get_request_by_id: callable(instance, sysid) -> Dict|None  # alternative to `requests`
      - instance: Any  # passed to get_request_by_id
      - expected_url_suffix: str  # if present, require current_url.endswith(suffix)
    """
    if (
        not "item" in config
        or not "quantity" in config
        or not "configuration" in config
    ):
        raise ValueError("Missing required fields in config")

    # Check whether we have messages
    if not messages:
        raise ValueError("Messages must not be empty")

    # Extract last message content
    content = messages[-1].get("content", "")

    # Extract all URLs — markdown links first, then bare URLs
    seen = set()
    urls = []
    for m in re.finditer(r"\[.*?\]\((https?://[^)]+)\)", content):
        url = m.group(1)
        if url not in seen:
            seen.add(url)
            urls.append(url)
    for m in re.finditer(r"https?://\S+", content):
        url = m.group(0).rstrip(")].,")
        if url not in seen:
            seen.add(url)
            urls.append(url)
    if not urls:
        return 0

    def extract_sys_id(url: str) -> str | None:
        """
        Return the 32-hex sys_id from a ServiceNow URL, or None if not found.
        Handles encoded target URLs like .../params/target/incident.do%3Fsys_id%3D<id>
        """
        # Unquote repeatedly (some SN URLs are doubly-encoded)
        for _ in range(3):
            new = parse.unquote(url)
            if new == url:
                break
            url = new

        m = re.search(r"(?:[?&])sys_id=([0-9a-f]{32})", url, re.IGNORECASE)
        return m.group(1) if m else None

    sysid = None
    page_url = None
    for raw_url in urls:
        candidate = parse.unquote(raw_url)
        sysid = extract_sys_id(candidate)
        if sysid:
            page_url = candidate
            break
    if not sysid:
        return 0

    # Detect table from URL to determine lookup strategy
    is_req_item = "sc_req_item" in page_url

    def _api_get(table, params):
        resp = requests.request(
            method="GET",
            url=os.getenv("SERVICENOW_INSTANCE_URL", "").rstrip("/") + f"/api/now/table/{table}",
            headers={
                "Content-Type": "application/json",
                "Accept": "application/json",
                **json.loads(os.getenv("SERVICENOW_EXTRA_HTTP_HEADERS", "{}")),
            },
            params=params,
        )
        resp.raise_for_status()
        if type(resp) == dict:
            return resp["result"]
        return resp.json()["result"]

    if is_req_item:
        # URL points directly to sc_req_item — look it up directly
        # Use cat_item display value for description matching
        req_item_records = _api_get(
            "sc_req_item",
            {
                "sysparm_query": f"sys_id={sysid}",
                "sysparm_fields": "sys_id,cat_item,short_description,quantity",
                "sysparm_display_value": "all",
            },
        )
    else:
        # URL points to sc_request — look up request, then find its item
        request_records = _api_get("sc_request", {"sysparm_query": f"sys_id={sysid}"})
        if len(request_records) == 0:
            return 0

        req_item_records = _api_get(
            "sc_req_item",
            {
                "sysparm_query": f"request={sysid}",
                "sysparm_fields": "sys_id,cat_item,short_description,quantity",
                "sysparm_display_value": "all",
            },
        )

    if len(req_item_records) == 0:
        return 0
    if len(req_item_records) > 1:
        return 0

    # get options for item
    req_item_record = req_item_records[0]
    req_item_record_sys_id = req_item_record["sys_id"]["value"]
    req_item_options = _api_get(
        "sc_item_option_mtom",
        {
            "sysparm_query": f"request_item={req_item_record_sys_id}",
            "sysparm_fields": "sc_item_option.value,sc_item_option.item_option_new.question_text",
        },
    )

    req_item_record["options"] = {
        opt["sc_item_option.item_option_new.question_text"]: opt["sc_item_option.value"]
        for opt in req_item_options
    }

    expected_item = str(config.get("item", "")).strip().lower()
    got_item = req_item_record.get("cat_item", "")
    if isinstance(got_item, dict) and "display_value" in got_item:
        got_item = got_item["display_value"]
    got_item = str(got_item).strip().lower()
    if got_item != expected_item:
        return 0

    if "description" in config:
        expected_desc = str(config.get("description", "")).strip().lower()
        got_desc = req_item_record.get("short_description", "")
        if isinstance(got_desc, dict) and "display_value" in got_desc:
            got_desc = got_desc["display_value"]
        got_desc = str(got_desc).strip().lower()
        if got_desc != expected_desc:
            return 0

    expected_qty = str(config.get("quantity"))
    got_qty = req_item_record.get("quantity", "")
    if isinstance(got_qty, dict) and "display_value" in got_qty:
        got_qty = got_qty["display_value"]
    got_qty = str(got_qty)
    if got_qty != expected_qty:
        return 0

    def option_match_heuristic(value, option):
        def _process(x):
            x = str(x).lower()
            x = x.replace("_", "")
            x = x.replace(" ", "")
            return x

        return _process(value) == _process(option)

    options = req_item_record.get("options", {})
    requested_cfg = config.get("configuration", {})

    for k, pair in requested_cfg.items():
        got_val = options.get(k, "")

        if isinstance(pair, (list, tuple)) and len(pair) == 2:
            # Format: [element_type, value]
            element_type, expected_val = pair
            et = str(element_type).lower()
            if et in {"checkbox", "radio"}:
                if not option_match_heuristic(expected_val, got_val):
                    return 0
            elif et == "textarea":
                if str(expected_val).strip().lower() not in str(got_val).strip().lower():
                    return 0
            else:
                # Unknown element type -> fail safe
                return 0
        else:
            # Plain value format: direct heuristic comparison
            if not option_match_heuristic(pair, got_val):
                return 0

    return 1