From fa0dbc0b675563fae265317c6a6eb9f9ffd8f3a8 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:31:40 -0500 Subject: [PATCH 01/22] improve readme --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7f1cbe3..4dc68eb 100644 --- a/README.md +++ b/README.md @@ -27,26 +27,76 @@ Welcome to Vectorly's Web Hacker... **No API? No Problem!** ## What is a *Routine*? -> A Routine is a portable recipe for automating a web flow. It has: +> A **Routine** is a portable automation recipe that captures how to perform a specific task in any web app. -- name, description -- parameters: input values the routine needs -- operations: ordered steps the browser executes +Define once. Reuse everywhere. Automate anything you can do in a browser. + +Each Routine includes: +- **name** — a human-readable identifier +- **description** — what the Routine does +- **parameters** — input values the Routine needs to run (e.g. URLs, credentials, text) +- **operations** — the ordered browser actions that perform the automation + +Example: +> Log in to a website, navigate to a dashboard, and export a report — all as a reusable Routine. ### Parameters -- Defined as typed inputs (see `src/data_models/production_routine.py:Parameter`). -- Each parameter has a `name`, `type`, `required`, and optional `default`/`examples`. -- Parameters are referenced inside operations using placeholder tokens like `{{argument_1}}`, `{{argument_2}}`. +- Defined as typed inputs (see [`Parameter`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py) class). +- Each parameter has required `name` and `description` fields, along with `type`, `required`, and optional `default`/`examples`. +- Parameters are referenced inside operations using placeholder tokens like `{{paramName}}` (see [Placeholder Interpolation](#placeholder-interpolation-) below). ### Operations -Operations are a typed list (see `RoutineOperationUnion`) executed in order: +Operations define the executable steps of a Routine. +They are represented as a **typed list** (see [`RoutineOperationUnion`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py)) and are executed sequentially by the browser agent. + +Each operation specifies a `type` and its parameters: + +- **navigate** — open a URL in the browser. + ```json + { "type": "navigate", "url": "https://example.com" } + ``` +- **sleep** — pause execution for a given duration (in seconds). + ```json + { "type": "sleep", "timeout_seconds": 1.5 } + ``` +- **fetch** — perform an HTTP request defined by an `endpoint` object (method, URL, headers, body, credentials). Optionally, store the response under a `session_storage_key`. + ```json + { + "type": "fetch", + "endpoint": { + "method": "GET", + "url": "https://api.example.com" + }, + "session_storage_key": "userData" + } + ``` +- **return** — return the value previously stored under a `session_storage_key`. + ```json + { "type": "return", "session_storage_key": "userData" } + ``` + +Example sequence: +```json +[ + { "type": "navigate", "url": "https://example.com/login" }, + { "type": "sleep", "timeout_seconds": 1 }, + { + "type": "fetch", + "endpoint": { + "method": "POST", + "url": "/auth", + "body": { "username": "{{user}}", "password": "{{pass}}" } + }, + "session_storage_key": "token" + }, + { "type": "return", "session_storage_key": "token" } +] +``` + +This defines a deterministic flow: open → wait → authenticate → return a session token. -- navigate: `{ "type": "navigate", "url": "https://example.com" }` -- sleep: `{ "type": "sleep", "timeout_seconds": 1.5 }` -- fetch: performs an HTTP request described by an `endpoint` object (method, url, headers, body, credentials) and can store results under a `session_storage_key`. -- return: returns the value previously stored under a `session_storage_key`. ### Placeholder Interpolation `{{...}}` @@ -166,6 +216,14 @@ if (!(Test-Path $chrome)) { ## HACK (reverse engineer) WEB APPS 👨🏻‍💻 +The reverse engineering process follows a simple three-step workflow: + +1. **Monitor** — Capture network traffic, storage events, and interactions while you manually perform the target task in Chrome +2. **Discover** — Let the AI agent analyze the captured data and generate a reusable Routine +3. **Execute** — Run the discovered Routine with different parameters to automate the task + +Each step is detailed below. Start by ensuring Chrome is running in debug mode (see [Launch Chrome in Debug Mode](#launch-chrome-in-debug-mode-🐞) above). + ### Monitor Browser While Performing Some Task Use the CDP browser monitor to block trackers and capture network, storage and interaction data while you manually perform tasks in Chrome. From 1e51086da6db6624182aa66d6d0f8908d6a45546 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:31:47 -0500 Subject: [PATCH 02/22] make src an importable package --- README.md | 4 ++-- src/__init__.py | 0 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/__init__.py diff --git a/README.md b/README.md index 4dc68eb..42b0e76 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,7 @@ python scripts/browser_monitor.py \ --host 127.0.0.1 \ --port 9222 \ --output-dir ./cdp_captures \ - --url https://www.example.com + --url about:blank ``` Attach to existing tab: @@ -251,7 +251,7 @@ python scripts/browser_monitor.py --tab-id Create a new tab automatically: ``` -python scripts/browser_monitor.py --url https://example.com +python scripts/browser_monitor.py --url about:blank ``` Incognito new tab (only when not supplying TAB_ID): diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 From 25fa0f849f20284b4d95d8895d8febe249ee2286 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:31:58 -0500 Subject: [PATCH 03/22] improve readme --- README.md | 109 +++++++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 42b0e76..c125529 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ This substitutes parameter values and injects `auth_token` from cookies. The JSO - Windows (PowerShell): `iwr https://astral.sh/uv/install.ps1 -UseBasicParsing | iex` - OpenAI API key -## Setup Your Environment 🔧 +## Set up Your Environment 🔧 ```bash # 1) Clone and enter the repo @@ -224,15 +224,16 @@ The reverse engineering process follows a simple three-step workflow: Each step is detailed below. Start by ensuring Chrome is running in debug mode (see [Launch Chrome in Debug Mode](#launch-chrome-in-debug-mode-🐞) above). -### Monitor Browser While Performing Some Task +### 0. Legal & Privacy Notice ⚠️ +Reverse-engineering and automating a website can violate terms of service. Store captures securely and scrub any sensitive fields before sharing. -Use the CDP browser monitor to block trackers and capture network, storage and interaction data while you manually perform tasks in Chrome. +### 1. Monitor Browser While Performing Some Task -Prereq: Chrome running in debug mode (see above). Get a `TAB_ID` from `chrome://inspect/#devices` or `http://127.0.0.1:9222/json`. +Use the CDP browser monitor to block trackers and capture network, storage, and interaction data while you manually perform the task in Chrome. -Basic usage: +**Run this command to start monitoring:** -``` +```bash python scripts/browser_monitor.py \ --host 127.0.0.1 \ --port 9222 \ @@ -240,56 +241,9 @@ python scripts/browser_monitor.py \ --url about:blank ``` -Attach to existing tab: - -``` -python scripts/browser_monitor.py -# or -python scripts/browser_monitor.py --tab-id -``` - -Create a new tab automatically: - -``` -python scripts/browser_monitor.py --url about:blank -``` - -Incognito new tab (only when not supplying TAB_ID): +The script will open a new tab (starting at `about:blank`). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically. -``` -python scripts/browser_monitor.py --incognito --url https://example.com -``` - -Attach without navigating (keep current page): - -``` -python scripts/browser_monitor.py --tab-id --no-navigate -``` - -Control output directory behavior: - -``` -# default is to clear; to keep previous outputs -python scripts/browser_monitor.py --keep-output -``` - -Select which resource types to capture (default: XHR, Fetch): - -``` -python scripts/browser_monitor.py --tab-id \ - --capture-resources XHR Fetch -``` - -Disable clearing cookies/storage (cleared by default): - -``` -python scripts/browser_monitor.py --tab-id --no-clear-all -# or granular -python scripts/browser_monitor.py --tab-id --no-clear-cookies -python scripts/browser_monitor.py --tab-id --no-clear-storage -``` - -Output structure (under `--output-dir`, default `./cdp_captures`): +**Output structure** (under `--output-dir`, default `./cdp_captures`): ``` cdp_captures/ @@ -306,15 +260,17 @@ cdp_captures/ │ └── events.jsonl ``` -Tip: Keep Chrome focused while monitoring and perform the target flow (search, checkout, etc.). Press Ctrl+C to stop; the script will consolidate transactions and produce a HAR automatically. +Tip: Keep Chrome focused while monitoring and perform the target flow (search, checkout, etc.). Press Ctrl+C to stop; the script will consolidate transactions and produce a HTTP Archive (HAR) automatically. + +### 2. Run Routine-Discovery Agent (Our Very Smart AI with Very Good Prompt🔮)🤖 -### Run Routine Discovery Agent (Our Very Smart AI with Very Good Prompt🔮)🤖 +Use the **routine-discovery pipeline** to analyze captured data and synthesize a reusable Routine (`navigate → fetch → return`). -Use the routine discovery pipeline to generate a reusable Routine (navigate → fetch → return) from your captured network data. +**Prerequisites:** You’ve already captured a session with the browser monitor (`./cdp_captures` exists). -Prereq: You have already captured data with the browser monitor (see above) and have `./cdp_captures` populated. +**Run the discovery agent:** -Basic usage: +> ⚠️ **Important:** You must specify your own `--task` parameter. The example below is just for demonstration—replace it with a description of what you want to automate. ``` python scripts/discover_routines.py \ @@ -324,9 +280,15 @@ python scripts/discover_routines.py \ --llm-model gpt-5 ``` +**Example tasks:** +- `"recover the api endpoints for searching for trains and their prices"` (shown above) +- `"discover how to search for flights and get pricing"` +- `"find the API endpoint for user authentication"` +- `"extract the endpoint for submitting a job application"` + Arguments: -- **--task**: What you want to achieve? What API endpoint should it discover? +- **--task**: A clear description of what you want to automate. This guides the AI agent to identify which network requests to extract and convert into a Routine. Examples: searching for products, booking appointments, submitting forms, etc. - **--cdp-captures-dir**: Root of prior CDP capture output (default: `./cdp_captures`) - **--output-dir**: Directory to write results (default: `./routine_discovery_output`) - **--llm-model**: LLM to use for reasoning/parsing (default: `gpt-5`) @@ -341,11 +303,22 @@ routine_discovery_output/ └── routine.json # Final Routine model (name, parameters, operations) ``` -### Execute the Discovered Routines 🏃 +### 3. Execute the Discovered Routines 🏃 -Run the example routine: +⚠️ **Important:** If you have a string-typed parameter used in a JSON body field, it may need to be escaped. When the agent generates routines, string parameters are sometimes placed as `"{{PARAM}}"` when they should be `"\"{{PARAM}}\""` to ensure proper JSON string escaping. +**Example:** If you see: +```json +"field": "{{paramName}}" +``` +And `paramName` is a string parameter, manually change it to: +```json +"field": "\"{{paramName}}\"" +``` + +This ensures the parameter value is properly quoted as a JSON string when substituted. +Run the example routine: ``` # Using a parameters file (see examples in `scripts/execute_routine.py`): @@ -370,6 +343,8 @@ python scripts/execute_routine.py \ --parameters-path routine_discovery_output/test_parameters.json ``` +**Alternative:** Deploy your routine to [console.vectorly.app](https://console.vectorly.app) to expose it as an API endpoint or MCP server for use in production environments. + ## Common Issues ⚠️ - Chrome not detected / cannot connect to DevTools @@ -379,6 +354,14 @@ python scripts/execute_routine.py \ - `OPENAI_API_KEY` not set - Export the key in your shell or create a `.env` file and run via `uv run` (dotenv is loaded). +- `No such file or directory: './cdp_captures/network/transactions/N/A'` or similar transaction path errors + + - The agent cannot find any network transactions relevant to your task. This usually means: + - The `--task` description doesn't match what you actually performed during monitoring + - The relevant network requests weren't captured (they may have been blocked or filtered) + - The task description is too vague or too specific + + - **Fix:** Reword your `--task` parameter to more accurately describe what you did during the monitoring step, or re-run the browser monitor and ensure you perform the exact actions you want to automate. ## Coming Soon 🔮 From 2d1722dcce891b4923c0fd0fe267290d15229dd4 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:00 -0500 Subject: [PATCH 04/22] add console link in the readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c125529..e97fb74 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@

+

From b9e979a83d93b57b144dae624f38c4bcdfa9d859 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:03 -0500 Subject: [PATCH 05/22] paramname --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e97fb74..0e5903e 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Example: - Defined as typed inputs (see [`Parameter`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py) class). - Each parameter has required `name` and `description` fields, along with `type`, `required`, and optional `default`/`examples`. -- Parameters are referenced inside operations using placeholder tokens like `{{paramName}}` (see [Placeholder Interpolation](#placeholder-interpolation-) below). +- Parameters are referenced inside operations using placeholder tokens like `"{{paramName}}"` or `"\"{{paramName}}\""` (see [Placeholder Interpolation](#placeholder-interpolation-) below). ### Operations From 38f9bb9e160a323a623f1b11e1eee76fbdf4cbd1 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:05 -0500 Subject: [PATCH 06/22] update example sequence --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e5903e..de9e26b 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Example sequence: "endpoint": { "method": "POST", "url": "/auth", - "body": { "username": "{{user}}", "password": "{{pass}}" } + "body": { "username": "\"{{user}}\"", "password": "\"{{pass}}\"" } }, "session_storage_key": "token" }, From e2f5269ea2c2e5c89adacd2f6ff806253b14416d Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:07 -0500 Subject: [PATCH 07/22] update quote format --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index de9e26b..a3ba356 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Example: - Defined as typed inputs (see [`Parameter`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py) class). - Each parameter has required `name` and `description` fields, along with `type`, `required`, and optional `default`/`examples`. -- Parameters are referenced inside operations using placeholder tokens like `"{{paramName}}"` or `"\"{{paramName}}\""` (see [Placeholder Interpolation](#placeholder-interpolation-) below). +- Parameters are referenced inside operations using placeholder tokens like `"{{paramName}}"` or `\"{{paramName}}\"` (see [Placeholder Interpolation](#placeholder-interpolation-) below). ### Operations @@ -103,7 +103,7 @@ This defines a deterministic flow: open → wait → authenticate → return a s Placeholders inside operation fields are resolved at runtime: -- Parameter placeholders: `{{paramName}}` → substituted from routine parameters +- Parameter placeholders: `"{{paramName}}"` or `\"{{paramName}}\"` → substituted from routine parameters - Storage placeholders (read values from the current session): - `{{sessionStorage:myKey.path.to.value}}` - `{{localStorage:myKey}}` From 63193cb91c7e2650fba1a6edaa0a4f08f3df7537 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:09 -0500 Subject: [PATCH 08/22] update example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a3ba356..5ee8f8a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Each Routine includes: - **operations** — the ordered browser actions that perform the automation Example: -> Log in to a website, navigate to a dashboard, and export a report — all as a reusable Routine. +> Navigate to a dashboard, search based on keywords, and return results — all as a reusable Routine. ### Parameters From 950d00870cc10217c2be4bad09c26193ee704ffa Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:12 -0500 Subject: [PATCH 09/22] update example endpoint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ee8f8a..f05b465 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ Interpolation occurs before an operation executes. For example, a fetch endpoint "type": "fetch", "endpoint": { "method": "GET", - "url": "https://api.example.com/search?arg1={{argument_1}}&arg2={{argument_2}}", + "url": "https://api.example.com/search?paramName1=\"{{paramName1}}\"¶mName2=\"{{paramName1}}\"", "headers": { "Authorization": "Bearer {{cookie:auth_token}}" }, From dc78b705e6cab9f28460815aabb3fb307b6583d9 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:14 -0500 Subject: [PATCH 10/22] pluralize prompt --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f05b465..142325c 100644 --- a/README.md +++ b/README.md @@ -263,7 +263,7 @@ cdp_captures/ Tip: Keep Chrome focused while monitoring and perform the target flow (search, checkout, etc.). Press Ctrl+C to stop; the script will consolidate transactions and produce a HTTP Archive (HAR) automatically. -### 2. Run Routine-Discovery Agent (Our Very Smart AI with Very Good Prompt🔮)🤖 +### 2. Run Routine-Discovery Agent (Our Very Smart AI with Very Good Prompts🔮)🤖 Use the **routine-discovery pipeline** to analyze captured data and synthesize a reusable Routine (`navigate → fetch → return`). From 93eb7da559a22fcf4e150e9bcbe448c7d0e2af7f Mon Sep 17 00:00:00 2001 From: Dima Vremekno Date: Sun, 2 Nov 2025 20:35:21 -0500 Subject: [PATCH 11/22] addign stuff --- example_routines/jet_blue_input.json | 6 + .../jetblue_one_way_flight_search.json | 111 +++++++++ ip_test_routine.json | 36 +++ .../message_history.json | 114 ++++++++++ .../root_transaction.json | 8 + routine_discovery_output_old/routine.json | 188 ++++++++++++++++ .../test_parameters.json | 7 + .../transaction_0/extracted_variables.json | 212 ++++++++++++++++++ .../transaction_0/resolved_variables.json | 24 ++ .../transaction_1/extracted_variables.json | 42 ++++ .../transaction_1/resolved_variables.json | 24 ++ .../transaction_2/extracted_variables.json | 139 ++++++++++++ scripts/browser_monitor.py | 9 - scripts/execute_routine.py | 4 +- src/cdp/routine_execution.py | 74 ++++-- src/data_models/llm_responses.py | 2 +- src/data_models/production_routine.py | 22 +- src/routine_discovery/agent.py | 75 +++++-- src/routine_discovery/context_manager.py | 3 +- 19 files changed, 1042 insertions(+), 58 deletions(-) create mode 100644 example_routines/jet_blue_input.json create mode 100644 example_routines/jetblue_one_way_flight_search.json create mode 100644 ip_test_routine.json create mode 100644 routine_discovery_output_old/message_history.json create mode 100644 routine_discovery_output_old/root_transaction.json create mode 100644 routine_discovery_output_old/routine.json create mode 100644 routine_discovery_output_old/test_parameters.json create mode 100644 routine_discovery_output_old/transaction_0/extracted_variables.json create mode 100644 routine_discovery_output_old/transaction_0/resolved_variables.json create mode 100644 routine_discovery_output_old/transaction_1/extracted_variables.json create mode 100644 routine_discovery_output_old/transaction_1/resolved_variables.json create mode 100644 routine_discovery_output_old/transaction_2/extracted_variables.json diff --git a/example_routines/jet_blue_input.json b/example_routines/jet_blue_input.json new file mode 100644 index 0000000..4baa44a --- /dev/null +++ b/example_routines/jet_blue_input.json @@ -0,0 +1,6 @@ +{ + "origin": "BOS", + "destination": "JFK", + "date": "2026-01-15", + "adults": 1 +} \ No newline at end of file diff --git a/example_routines/jetblue_one_way_flight_search.json b/example_routines/jetblue_one_way_flight_search.json new file mode 100644 index 0000000..70437db --- /dev/null +++ b/example_routines/jetblue_one_way_flight_search.json @@ -0,0 +1,111 @@ +{ + "routine_id": "550e8400-e29b-41d4-a716-446655440005", + "name": "jetblue_search_one_way", + "description": "Search for one-way flights on JetBlue. Use this when users want to find JetBlue flights for a specific route and date. Returns available itineraries with pricing, schedules, and booking options. Best for users who prefer JetBlue or want to compare with other airlines.", + "incognito": true, + "operations": [ + { + "type": "navigate", + "url": "https://www.jetblue.com/booking/cb-flights" + }, + { + "type": "sleep", + "timeout_seconds": 2 + }, + { + "type": "fetch", + "endpoint": { + "headers": { + "sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"", + "sec-ch-ua-mobile": "?0", + "Accept": "application/json, text/plain, */*", + "X-B3-SpanId": "{{uuid}}", + "ocp-apim-subscription-key": "{{localStorage:jb-app-config-original.crystalBlueSubscriptionKey}}", + "sec-ch-ua-platform": "\"macOS\"", + "Referer": "https://www.jetblue.com", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", + "X-B3-TraceId": "{{epoch_milliseconds}}", + "Content-Type": "application/json" + }, + "method": "POST", + "body": { + "awardBooking": false, + "searchComponents": [ + { + "date": "\"{{date}}\"", + "from": "\"{{origin}}\"", + "to": "\"{{destination}}\"" + } + ], + "travelerTypes": [ + { + "type": "ADULT", + "quantity": "{{adults}}" + } + ] + }, + "url": "https://cb-api.jetblue.com/cb-flight-search/v1/search/NGB?digb_enable_cb_profile=true&crystal_blue_price_summary=true&crystal_blue_seats_extras=true&digb_acfp_previewseatmap=true&digb_acfp_opsseatmap=true&is_cb_flow=true" + }, + "session_storage_key": "jetblue_search_one_way_result" + }, + { + "type": "return", + "session_storage_key": "jetblue_search_one_way_result" + } +], + "parameters": [ + { + "name": "adults", + "description": "Number of adult travelers (1-9). Defaults to 1 for single traveler searches. For group bookings, specify the total number of adults.", + "default": 1, + "type": "integer", + "examples": [ + 1, + 2, + 4 + ], + "required": true + }, + { + "name": "origin", + "description": "Origin airport IATA code (3-letter code like BOS, JFK, LAX). Use airport codes, not city names. For major cities, use the primary airport code.", + "default": "BOS", + "type": "string", + "examples": [ + "BOS", + "JFK", + "LAX", + "SFO", + "FLL" + ], + "required": true + }, + { + "name": "destination", + "description": "Destination airport IATA code (3-letter code like SFO, JFK, LAX). Use airport codes, not city names. For major cities, use the primary airport code.", + "default": "SFO", + "type": "string", + "examples": [ + "SFO", + "JFK", + "BOS", + "LAX", + "FLL" + ], + "required": true + }, + { + "default": "2025-11-13", + "examples": [ + "2025-11-13", + "2025-12-01", + "2026-01-15" + ], + "name": "date", + "format": "YYYY-MM-DD", + "description": "Departure date in YYYY-MM-DD format. Use future dates only. For best results, search 1-6 months in advance.", + "type": "date", + "required": true + } + ] + } \ No newline at end of file diff --git a/ip_test_routine.json b/ip_test_routine.json new file mode 100644 index 0000000..2ba317f --- /dev/null +++ b/ip_test_routine.json @@ -0,0 +1,36 @@ +{ + "id": "Routine_2f2859d3-3edf-4b13-ab7a-59ef06b6871c", + "created_at": 1761960892, + "updated_at": 1761960892, + "name": "ip_test", + "description": "Navigate to ipify.org and get the IP address.", + "operations": [ + { + "type": "navigate", + "url": "https://api.ipify.org/" + }, + { + "type": "sleep", + "timeout_seconds": 2.5 + }, + { + "type": "fetch", + "endpoint": { + "url": "https://api.ipify.org/", + "description": "Get IP address.", + "method": "GET", + "headers": {}, + "body": {}, + "credentials": "same-origin" + }, + "session_storage_key": "ip_address" + }, + { + "type": "return", + "session_storage_key": "ip_address" + } + ], + "incognito": true, + "parameters": [ + ] + } \ No newline at end of file diff --git a/routine_discovery_output_old/message_history.json b/routine_discovery_output_old/message_history.json new file mode 100644 index 0000000..36cdc38 --- /dev/null +++ b/routine_discovery_output_old/message_history.json @@ -0,0 +1,114 @@ +[ + { + "role": "system", + "content": "\n You are a helpful assistant that is an expert in parsing network traffic.\n You need to identify one or more network transactions that directly correspond to the user's requested task.\n You have access to vectorstore that contains network transactions and storage data\n (cookies, localStorage, sessionStorage, etc.).\n " + }, + { + "role": "user", + "content": "Task description: recover the spirit one way flight option and price api" + }, + { + "role": "user", + "content": "These are the possible network transaction ids you can choose from: ['20251030_1761863980617_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863968610_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863992134_www.spirit.com_api_prod-availability_api_availability_v2_lowfare', '20251030_1761863969444_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863968655_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863971857_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967634_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863977978_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863969655_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', '20251030_1761863970672_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863973741_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967901_content.spirit.com_api_content_en-US', '20251030_1761863973061_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863994486_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967911_content.spirit.com_api_content_en-US', '20251030_1761863978282_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863970591_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967972_p11.techlab-cdn.com_h_b90dea8b4dec42619841bf216443707a', '20251030_1761863969778_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', '20251030_1761863976683_www.spirit.com_api_prod-availability_api_Calendar_availableDates', '20251030_1761863967772_content.spirit.com_api_content_en-US', '20251030_1761863992676_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863992744_content.spirit.com_api_content_en-US', '20251030_1761863992683_www.spirit.com_assets_i18n_flight-search-widget_en-US.json', '20251030_1761863967890_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863992734_content.spirit.com_api_content_en-US', '20251030_1761863967894_www.spirit.com_assets_i18n_flight-search-widget_en-US.json', '20251030_1761863985315_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967908_content.spirit.com_api_content_en-US', '20251030_1761863967669_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863997680_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967886_www.spirit.com_api_prod-station_api_resources_v2_stations', '20251030_1761863968177_content.spirit.com_api_content_en-US', '20251030_1761863992750_content.spirit.com_api_content_en-US', '20251030_1761863967655_tzm.px-cloud.net_ns', '20251030_1761863992730_content.spirit.com_api_content_en-US', '20251030_1761863971827_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863992477_content.spirit.com_api_content_en-US', '20251030_1761863969842_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863992480_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863967913_content.spirit.com_api_content_en-US', '20251030_1761863976688_www.spirit.com_api_prod-apo_api_apo', '20251030_1761863967898_content.spirit.com_api_content_en-US', '20251030_1761863992726_www.spirit.com_api_prod-station_api_resources_carriers', '20251030_1761863992474_www.spirit.com_api_prod-token_api_v1_token', '20251030_1761863991858_www.spirit.com_api_prod-booking_api_booking_reset', '20251030_1761863967905_content.spirit.com_api_content_en-US', '20251030_1761863988901_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863992483_www.spirit.com_assets_i18n_book-path_en-US.json', '20251030_1761863992679_www.spirit.com_assets_i18n_flight_en-US.json']" + }, + { + "role": "user", + "content": "Please respond in the following format: {'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}, 'Method': {'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], 'title': 'Method', 'type': 'string'}}, 'description': \"Response from the LLM for identifying the network transaction that directly corresponds to\\nthe user's requested task. \", 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}, 'method': {'$ref': '#/$defs/Method'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['transaction_id', 'description', 'url', 'method', 'explanation', 'confidence_level'], 'title': 'TransactionIdentificationResponse', 'type': 'object'}" + }, + { + "role": "assistant", + "content": "{'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}, 'Method': {'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], 'title': 'Method', 'type': 'string'}}, 'description': \"Response from the LLM for identifying the network transaction that directly corresponds to\\nthe user's requested task. \", 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}, 'method': {'$ref': '#/$defs/Method'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['transaction_id', 'description', 'url', 'method', 'explanation', 'confidence_level'], 'title': 'TransactionIdentificationResponse', 'type': 'object', 'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'description': 'Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'explanation': 'This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .', 'confidence_level': 'high'}" + }, + { + "role": "assistant", + "content": "{\"transaction_id\":\"20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search\",\"description\":\"Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.\",\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"method\":\"POST\",\"explanation\":\"This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .\",\"confidence_level\":\"high\"}" + }, + { + "role": "user", + "content": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search have been added to the vectorstore in full (including response bodies).Please confirm that the identified transaction is correct and that it directly corresponds to the user's requested task:recover the spirit one way flight option and price apiPlease respond in the following format: {'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}}, 'description': \"Response obejct for confirming the identified network transactions that directly correspond to\\nthe user's requested task.\", 'properties': {'is_correct': {'title': 'Is Correct', 'type': 'boolean'}, 'confirmed_transaction_id': {'title': 'Confirmed Transaction Id', 'type': 'string'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['is_correct', 'confirmed_transaction_id', 'explanation', 'confidence_level'], 'title': 'TransactionConfirmationResponse', 'type': 'object'}" + }, + { + "role": "assistant", + "content": "{'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}}, 'description': \"Response obejct for confirming the identified network transactions that directly correspond to\\nthe user's requested task.\", 'properties': {'is_correct': {'title': 'Is Correct', 'type': 'boolean'}, 'confirmed_transaction_id': {'title': 'Confirmed Transaction Id', 'type': 'string'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['is_correct', 'confirmed_transaction_id', 'explanation', 'confidence_level'], 'title': 'TransactionConfirmationResponse', 'type': 'object', 'is_correct': true, 'confirmed_transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'explanation': 'Yes. This POST to https://www.spirit.com/api/prod-availability/api/availability/v3/search contains a single-day search window (beginDate == endDate) with origin/destination and passenger details, which is Spirit’s one-way availability search that returns flight options and their prices.', 'confidence_level': 'high'}" + }, + { + "role": "user", + "content": "Please extract the variables from the requests of identified network transactions: [{'request': {'requestId': '5580.247', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"BOS\"],\"destinationStationCodes\":[\"MIA\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"2025-10-31\",\"endDate\":\"2025-10-31\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":1}]},\"codes\":{\"currency\":\"USD\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}}]Please respond in the following format: {'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object'}Mark each variable with requires_resolution=True if we need to dynamically resolve this variable at runtime.If we can most likely hardcode this value, mark requires_resolution=False.system variables are related to the device or browser environment, and are not used to identify the user.token and cookie values are not used to identify the user: these may need to be resolved at runtime.Only the actual values of the variables (token/cookies, etc.) should be placed into the observed_value field.The values of values_to_scan_for will then be used to scan the storage and transactions for the source of the variable so only include the actual values of the variables.values_to_scan_for should be possible substrings that will likely be present in the response body of a network transaction or a storage entry value.This is necessary to figure out where the variable is coming from." + }, + { + "role": "assistant", + "content": "{'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object', 'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'variables': [{'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'eyJhbGciOiJSUzI1NiIsInR5cCI6Ik', 'KZYU5d88-7MUiPQ16Dt3', 'U1NJLjIifQ.bw8vxEnKZYU5d88', 'Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ'], 'description': 'Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.'}, {'type': 'token', 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'originStationCode', 'observed_value': 'BOS', 'values_to_scan_for': ['BOS'], 'description': 'Origin IATA station code for one-way search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'destinationStationCode', 'observed_value': 'MIA', 'values_to_scan_for': ['MIA'], 'description': 'Destination IATA station code for one-way search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'beginDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (start of search window).'}, {'type': 'argument', 'requires_resolution': True, 'name': 'endDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (end of search window). Same as beginDate for one-way single-day search.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'searchDestinationMacs', 'observed_value': 'false', 'values_to_scan_for': ['false'], 'description': 'Flag in stations block; false in observed request.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'filters.filter', 'observed_value': 'Default', 'values_to_scan_for': ['Default'], 'description': 'Top-level criteria filter mode.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'passengerType', 'observed_value': 'ADT', 'values_to_scan_for': ['ADT'], 'description': 'Passenger type code (Adult).'}, {'type': 'argument', 'requires_resolution': True, 'name': 'passengerCount_ADT', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Number of adult passengers.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'currency', 'observed_value': 'USD', 'values_to_scan_for': ['USD'], 'description': 'Pricing currency for the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'fareFilters.loyalty', 'observed_value': 'MonetaryOnly', 'values_to_scan_for': ['MonetaryOnly'], 'description': 'Fare loyalty filter used for pricing results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'fareFilters.classControl', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Class control setting for fare filtering.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'taxesAndFees', 'observed_value': 'TaxesAndFees', 'values_to_scan_for': ['TaxesAndFees'], 'description': 'Specifies how taxes and fees are handled in pricing.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'infantCount', 'observed_value': '0', 'values_to_scan_for': ['0'], 'description': 'Number of infants in the search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'birthDates', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Birthdates array for age-based pricing; empty in observed request.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'includeBundleAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include bundle availability in the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'includeWifiAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include Wi-Fi availability in the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'originalJourneyKeys', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Original journey keys (empty for new search).'}, {'type': 'argument', 'requires_resolution': False, 'name': 'originalBookingRecordLocator', 'observed_value': 'null', 'values_to_scan_for': ['null'], 'description': 'Original booking record locator (null for new search).'}], 'explanation': 'Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.'}" + }, + { + "role": "assistant", + "content": "{\"transaction_id\":\"20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search\",\"variables\":[{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"eyJhbGciOiJSUzI1NiIsInR5cCI6Ik\",\"KZYU5d88-7MUiPQ16Dt3\",\"U1NJLjIifQ.bw8vxEnKZYU5d88\",\"Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ\"],\"description\":\"Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.\"},{\"type\":\"token\",\"requires_resolution\":false,\"name\":\"Ocp-Apim-Subscription-Key\",\"observed_value\":\"3b6a6994753b4efc86376552e52b8432\",\"values_to_scan_for\":[\"3b6a6994753b4efc86376552e52b8432\",\"3b6a6994\",\"52e52b8432\"],\"description\":\"Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"originStationCode\",\"observed_value\":\"BOS\",\"values_to_scan_for\":[\"BOS\"],\"description\":\"Origin IATA station code for one-way search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"destinationStationCode\",\"observed_value\":\"MIA\",\"values_to_scan_for\":[\"MIA\"],\"description\":\"Destination IATA station code for one-way search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"beginDate\",\"observed_value\":\"2025-10-31\",\"values_to_scan_for\":[\"2025-10-31\"],\"description\":\"Departure date (start of search window).\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"endDate\",\"observed_value\":\"2025-10-31\",\"values_to_scan_for\":[\"2025-10-31\"],\"description\":\"Departure date (end of search window). Same as beginDate for one-way single-day search.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"searchDestinationMacs\",\"observed_value\":\"false\",\"values_to_scan_for\":[\"false\"],\"description\":\"Flag in stations block; false in observed request.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"filters.filter\",\"observed_value\":\"Default\",\"values_to_scan_for\":[\"Default\"],\"description\":\"Top-level criteria filter mode.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"passengerType\",\"observed_value\":\"ADT\",\"values_to_scan_for\":[\"ADT\"],\"description\":\"Passenger type code (Adult).\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"passengerCount_ADT\",\"observed_value\":\"1\",\"values_to_scan_for\":[\"1\"],\"description\":\"Number of adult passengers.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"currency\",\"observed_value\":\"USD\",\"values_to_scan_for\":[\"USD\"],\"description\":\"Pricing currency for the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"fareFilters.loyalty\",\"observed_value\":\"MonetaryOnly\",\"values_to_scan_for\":[\"MonetaryOnly\"],\"description\":\"Fare loyalty filter used for pricing results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"fareFilters.classControl\",\"observed_value\":\"1\",\"values_to_scan_for\":[\"1\"],\"description\":\"Class control setting for fare filtering.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"taxesAndFees\",\"observed_value\":\"TaxesAndFees\",\"values_to_scan_for\":[\"TaxesAndFees\"],\"description\":\"Specifies how taxes and fees are handled in pricing.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"infantCount\",\"observed_value\":\"0\",\"values_to_scan_for\":[\"0\"],\"description\":\"Number of infants in the search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"birthDates\",\"observed_value\":\"[]\",\"values_to_scan_for\":[\"[]\"],\"description\":\"Birthdates array for age-based pricing; empty in observed request.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"includeBundleAvailability\",\"observed_value\":\"true\",\"values_to_scan_for\":[\"true\"],\"description\":\"Whether to include bundle availability in the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"includeWifiAvailability\",\"observed_value\":\"true\",\"values_to_scan_for\":[\"true\"],\"description\":\"Whether to include Wi-Fi availability in the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"originalJourneyKeys\",\"observed_value\":\"[]\",\"values_to_scan_for\":[\"[]\"],\"description\":\"Original journey keys (empty for new search).\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"originalBookingRecordLocator\",\"observed_value\":\"null\",\"values_to_scan_for\":[\"null\"],\"description\":\"Original booking record locator (null for new search).\"}],\"explanation\":\"Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.\"}" + }, + { + "role": "user", + "content": "Please resolve the variable: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJThe variable was found in the following storage sources: []The variable was found in the following transactions ids: ['20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token']These transactions are added to the vectorstore in full (including response bodies).Please respond in the following format: {'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object'}Dot paths should be like this: 'key.data.items[0].id', 'path.to.valiable.0.value', etc.For paths in transaction responses, start with the first key of the response bodyFor paths in storage, start with the cookie, local storage, or session storage entry name" + }, + { + "role": "assistant", + "content": "{'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object', 'variable': {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.'}, 'session_storage_source': None, 'transaction_source': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'dot_path': 'token'}, 'explanation': 'The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.'}" + }, + { + "role": "assistant", + "content": "{\"variable\":{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.\"},\"session_storage_source\":null,\"transaction_source\":{\"transaction_id\":\"20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token\",\"dot_path\":\"token\"},\"explanation\":\"The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.\"}" + }, + { + "role": "user", + "content": "Please extract the variables from the requests of identified network transactions: [{'request': {'requestId': '5580.235', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"applicationName\":\"dotRezWeb\"}'}}, {'request': {'requestId': '5580.288', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'GET', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}}}]Please respond in the following format: {'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object'}Mark each variable with requires_resolution=True if we need to dynamically resolve this variable at runtime.If we can most likely hardcode this value, mark requires_resolution=False.system variables are related to the device or browser environment, and are not used to identify the user.token and cookie values are not used to identify the user: these may need to be resolved at runtime.Only the actual values of the variables (token/cookies, etc.) should be placed into the observed_value field.The values of values_to_scan_for will then be used to scan the storage and transactions for the source of the variable so only include the actual values of the variables.values_to_scan_for should be possible substrings that will likely be present in the response body of a network transaction or a storage entry value.This is necessary to figure out where the variable is coming from." + }, + { + "role": "assistant", + "content": "{'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object', 'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'variables': [{'type': 'argument', 'requires_resolution': False, 'name': 'applicationName', 'observed_value': 'dotRezWeb', 'values_to_scan_for': ['dotRezWeb'], 'description': 'Application name sent in the token-issuance POST body.'}, {'type': 'token', 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Subscription key required by Spirit APIs; typically static for the web app.'}, {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}], 'explanation': 'The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .'}" + }, + { + "role": "assistant", + "content": "{\"transaction_id\":\"20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token\",\"variables\":[{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"applicationName\",\"observed_value\":\"dotRezWeb\",\"values_to_scan_for\":[\"dotRezWeb\"],\"description\":\"Application name sent in the token-issuance POST body.\"},{\"type\":\"token\",\"requires_resolution\":false,\"name\":\"Ocp-Apim-Subscription-Key\",\"observed_value\":\"3b6a6994753b4efc86376552e52b8432\",\"values_to_scan_for\":[\"3b6a6994753b4efc86376552e52b8432\",\"3b6a6994\",\"52e52b8432\"],\"description\":\"Subscription key required by Spirit APIs; typically static for the web app.\"},{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.\"}],\"explanation\":\"The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .\"}" + }, + { + "role": "user", + "content": "Please resolve the variable: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJThe variable was found in the following storage sources: ['{\"type\": \"localStorageItemAdded\", \"origin\": \"https://www.spirit.com\", \"key\": \"token\", \"value\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\", \"timestamp\": 1761863976.68975}\\n', '{\"type\": \"localStorageItemAdded\", \"origin\": \"https://www.spirit.com\", \"key\": \"token\", \"value\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\", \"timestamp\": 1761863976.68975}\\n']The variable was found in the following transactions ids: []These transactions are added to the vectorstore in full (including response bodies).Please respond in the following format: {'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object'}Dot paths should be like this: 'key.data.items[0].id', 'path.to.valiable.0.value', etc.For paths in transaction responses, start with the first key of the response bodyFor paths in storage, start with the cookie, local storage, or session storage entry name" + }, + { + "role": "assistant", + "content": "{'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object', 'variable': {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize Spirit API requests; must be dynamically obtained and refreshed as it expires.'}, 'session_storage_source': {'type': 'localStorage', 'dot_path': 'token'}, 'transaction_source': None, 'explanation': 'The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\\\"token\\\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.'}" + }, + { + "role": "assistant", + "content": "{\"variable\":{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.\"},\"session_storage_source\":{\"type\":\"localStorage\",\"dot_path\":\"token\"},\"transaction_source\":null,\"explanation\":\"The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\\\"token\\\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.\"}" + }, + { + "role": "user", + "content": "Please construct the routine from the routine transactions: {'20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search': {'request': {'requestId': '5580.247', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"BOS\"],\"destinationStationCodes\":[\"MIA\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"2025-10-31\",\"endDate\":\"2025-10-31\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":1}]},\"codes\":{\"currency\":\"USD\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}, 'extracted_variables': {'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'variables': [{'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'eyJhbGciOiJSUzI1NiIsInR5cCI6Ik', 'KZYU5d88-7MUiPQ16Dt3', 'U1NJLjIifQ.bw8vxEnKZYU5d88', 'Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ'], 'description': 'Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.'}, {'type': , 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.'}, {'type': , 'requires_resolution': True, 'name': 'originStationCode', 'observed_value': 'BOS', 'values_to_scan_for': ['BOS'], 'description': 'Origin IATA station code for one-way search.'}, {'type': , 'requires_resolution': True, 'name': 'destinationStationCode', 'observed_value': 'MIA', 'values_to_scan_for': ['MIA'], 'description': 'Destination IATA station code for one-way search.'}, {'type': , 'requires_resolution': True, 'name': 'beginDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (start of search window).'}, {'type': , 'requires_resolution': True, 'name': 'endDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (end of search window). Same as beginDate for one-way single-day search.'}, {'type': , 'requires_resolution': False, 'name': 'searchDestinationMacs', 'observed_value': 'false', 'values_to_scan_for': ['false'], 'description': 'Flag in stations block; false in observed request.'}, {'type': , 'requires_resolution': False, 'name': 'filters.filter', 'observed_value': 'Default', 'values_to_scan_for': ['Default'], 'description': 'Top-level criteria filter mode.'}, {'type': , 'requires_resolution': True, 'name': 'passengerType', 'observed_value': 'ADT', 'values_to_scan_for': ['ADT'], 'description': 'Passenger type code (Adult).'}, {'type': , 'requires_resolution': True, 'name': 'passengerCount_ADT', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Number of adult passengers.'}, {'type': , 'requires_resolution': True, 'name': 'currency', 'observed_value': 'USD', 'values_to_scan_for': ['USD'], 'description': 'Pricing currency for the search results.'}, {'type': , 'requires_resolution': False, 'name': 'fareFilters.loyalty', 'observed_value': 'MonetaryOnly', 'values_to_scan_for': ['MonetaryOnly'], 'description': 'Fare loyalty filter used for pricing results.'}, {'type': , 'requires_resolution': False, 'name': 'fareFilters.classControl', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Class control setting for fare filtering.'}, {'type': , 'requires_resolution': False, 'name': 'taxesAndFees', 'observed_value': 'TaxesAndFees', 'values_to_scan_for': ['TaxesAndFees'], 'description': 'Specifies how taxes and fees are handled in pricing.'}, {'type': , 'requires_resolution': True, 'name': 'infantCount', 'observed_value': '0', 'values_to_scan_for': ['0'], 'description': 'Number of infants in the search.'}, {'type': , 'requires_resolution': True, 'name': 'birthDates', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Birthdates array for age-based pricing; empty in observed request.'}, {'type': , 'requires_resolution': False, 'name': 'includeBundleAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include bundle availability in the search results.'}, {'type': , 'requires_resolution': False, 'name': 'includeWifiAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include Wi-Fi availability in the search results.'}, {'type': , 'requires_resolution': False, 'name': 'originalJourneyKeys', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Original journey keys (empty for new search).'}, {'type': , 'requires_resolution': False, 'name': 'originalBookingRecordLocator', 'observed_value': 'null', 'values_to_scan_for': ['null'], 'description': 'Original booking record locator (null for new search).'}], 'explanation': 'Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.'}, 'resolved_variables': [{'variable': {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.'}, 'session_storage_source': None, 'transaction_source': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'dot_path': 'token'}, 'explanation': 'The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.'}]}, '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token': {'request': {'requestId': '5580.235', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"applicationName\":\"dotRezWeb\"}'}, 'extracted_variables': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'variables': [{'type': , 'requires_resolution': False, 'name': 'applicationName', 'observed_value': 'dotRezWeb', 'values_to_scan_for': ['dotRezWeb'], 'description': 'Application name sent in the token-issuance POST body.'}, {'type': , 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Subscription key required by Spirit APIs; typically static for the web app.'}, {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}], 'explanation': 'The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .'}, 'resolved_variables': [{'variable': {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}, 'session_storage_source': {'type': , 'dot_path': 'token'}, 'transaction_source': None, 'explanation': 'The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\"token\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.'}]}}. Please respond in the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': 'Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (str | None): Default value if not provided\\n examples (list[str]): Example values', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'required': {'default': True, 'title': 'Required', 'type': 'boolean'}, 'description': {'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Default'}, 'examples': {'default': [], 'items': {'type': 'string'}, 'title': 'Examples', 'type': 'array'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'anyOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'parameters': {'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations', 'parameters'], 'title': 'Routine', 'type': 'object'}. Fetch operations (1 to 1 with transactions) should be constructed as follows: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}}, 'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}. First step of the routine should be to navigate to the target web page and sleep for a bit of time (2-3 seconds). All fetch operations should be constructed as follows: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}}, 'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}. Parameters are only the most important arguments. You can inject variables by using the following syntax: {{parameter_name}} {{cookie:cookie_name}} {{sessionStorage:key.path.to.0.value}} {{local_storage:local_storage_name}}. You can hardcode unresolved variables to their observed values. You will want to navigate to the target page, then perform the fetch operations in the proper order. Browser variables should be hardcoded to observed values. If tokens or cookies are resolved, they should point to values in the session storage.You can navigate to other pages in the routine by using the navigate operation. Endpoints of the fetch operations should mimick observed network traffic requests! Every fetch operation result is written to session storage. At the end of the routine return the proper session storage value (likely containing the last fetch operation result). To feed output of a fetch into a subsequent fetch, you can save result to session storage and then use {sessionStorage:key.to.path}. " + }, + { + "role": "assistant", + "content": "{'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': 'Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (str | None): Default value if not provided\\n examples (list[str]): Example values', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'required': {'default': True, 'title': 'Required', 'type': 'boolean'}, 'description': {'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Default'}, 'examples': {'default': [], 'items': {'type': 'string'}, 'title': 'Examples', 'type': 'array'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'anyOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'parameters': {'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations', 'parameters'], 'title': 'Routine', 'type': 'object'}, 'name': 'spirit_one_way_search', 'description': 'Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .', 'operations': [{'type': 'navigate', 'url': 'https://www.spirit.com/'}, {'type': 'sleep', 'timeout_seconds': 2.5}, {'type': 'fetch', 'endpoint': {'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'description': 'Issue JWT used for Authorization: Bearer; response contains data.token per capture .', 'method': 'POST', 'headers': '{\"sec-ch-ua-platform\":\"\\\\\"macOS\\\\\"\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"}', 'body': '{\"applicationName\":\"dotRezWeb\"}'}, 'session_storage_key': 'token_response'}, {'type': 'fetch', 'endpoint': {'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'description': 'One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .', 'method': 'POST', 'headers': '{\"sec-ch-ua-platform\":\"\\\\\"macOS\\\\\"\",\"Authorization\":\"Bearer {{sessionStorage:token_response.data.token}}\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Accept-Language\":\"en-US\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"}', 'body': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"{{origin}}\"],\"destinationStationCodes\":[\"{{destination}}\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"{{date}}\",\"endDate\":\"{{date}}\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":{{adt_count}}}]}, \"codes\":{\"currency\":\"{{currency}}\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}, 'session_storage_key': 'availability_search_response'}, {'type': 'return', 'session_storage_key': 'availability_search_response'}], 'parameters': [{'name': 'origin', 'description': 'Origin IATA station code for the one-way search.', 'default': 'BOS', 'examples': ['BOS', 'LAX', 'DTW']}, {'name': 'destination', 'description': 'Destination IATA station code for the one-way search.', 'default': 'MIA', 'examples': ['MIA', 'FLL', 'LAS']}, {'name': 'date', 'description': 'Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.', 'default': '2025-10-31', 'examples': ['2025-10-31', '2025-11-15']}, {'name': 'adt_count', 'description': 'Number of adult (ADT) passengers.', 'default': '1', 'examples': ['1', '2']}, {'name': 'currency', 'description': 'Pricing currency code.', 'default': 'USD', 'examples': ['USD']}] }" + }, + { + "role": "assistant", + "content": "{\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue JWT used for Authorization: Bearer; response contains data.token per capture .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"applicationName\\\":\\\"dotRezWeb\\\"}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Authorization\\\":\\\"Bearer {{sessionStorage:token_response.data.token}}\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Accept-Language\\\":\\\"en-US\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"includeWifiAvailability\\\":true,\\\"criteria\\\":[{\\\"stations\\\":{\\\"originStationCodes\\\":[\\\"{{origin}}\\\"],\\\"destinationStationCodes\\\":[\\\"{{destination}}\\\"],\\\"searchDestinationMacs\\\":false},\\\"dates\\\":{\\\"beginDate\\\":\\\"{{date}}\\\",\\\"endDate\\\":\\\"{{date}}\\\"},\\\"filters\\\":{\\\"filter\\\":\\\"Default\\\"}}],\\\"passengers\\\":{\\\"types\\\":[{\\\"type\\\":\\\"ADT\\\",\\\"count\\\":{{adt_count}}}]}, \\\"codes\\\":{\\\"currency\\\":\\\"{{currency}}\\\"},\\\"fareFilters\\\":{\\\"loyalty\\\":\\\"MonetaryOnly\\\",\\\"types\\\":[],\\\"classControl\\\":1},\\\"taxesAndFees\\\":\\\"TaxesAndFees\\\",\\\"originalJourneyKeys\\\":[],\\\"originalBookingRecordLocator\\\":null,\\\"infantCount\\\":0,\\\"birthDates\\\":[],\\\"includeBundleAvailability\\\":true}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"parameters\":[{\"name\":\"origin\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"]},{\"name\":\"destination\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"]},{\"name\":\"date\",\"required\":true,\"description\":\"Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"]},{\"name\":\"adt_count\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":\"1\",\"examples\":[\"1\",\"2\"]},{\"name\":\"currency\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"]}]}" + }, + { + "role": "user", + "content": "Please productionize the routine (from previosu step): {\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue JWT used for Authorization: Bearer; response contains data.token per capture .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"applicationName\\\":\\\"dotRezWeb\\\"}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Authorization\\\":\\\"Bearer {{sessionStorage:token_response.data.token}}\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Accept-Language\\\":\\\"en-US\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"includeWifiAvailability\\\":true,\\\"criteria\\\":[{\\\"stations\\\":{\\\"originStationCodes\\\":[\\\"{{origin}}\\\"],\\\"destinationStationCodes\\\":[\\\"{{destination}}\\\"],\\\"searchDestinationMacs\\\":false},\\\"dates\\\":{\\\"beginDate\\\":\\\"{{date}}\\\",\\\"endDate\\\":\\\"{{date}}\\\"},\\\"filters\\\":{\\\"filter\\\":\\\"Default\\\"}}],\\\"passengers\\\":{\\\"types\\\":[{\\\"type\\\":\\\"ADT\\\",\\\"count\\\":{{adt_count}}}]}, \\\"codes\\\":{\\\"currency\\\":\\\"{{currency}}\\\"},\\\"fareFilters\\\":{\\\"loyalty\\\":\\\"MonetaryOnly\\\",\\\"types\\\":[],\\\"classControl\\\":1},\\\"taxesAndFees\\\":\\\"TaxesAndFees\\\",\\\"originalJourneyKeys\\\":[],\\\"originalBookingRecordLocator\\\":null,\\\"infantCount\\\":0,\\\"birthDates\\\":[],\\\"includeBundleAvailability\\\":true}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"parameters\":[{\"name\":\"origin\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"]},{\"name\":\"destination\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"]},{\"name\":\"date\",\"required\":true,\"description\":\"Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"]},{\"name\":\"adt_count\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":\"1\",\"examples\":[\"1\",\"2\"]},{\"name\":\"currency\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"]}]}You need to clean up this routine to follow the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'description': 'Target API URL with parameter placeholders', 'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Human-readable description the fetch request', 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod', 'description': 'HTTP method'}, 'headers': {'additionalProperties': True, 'description': 'Dictionary of headers, with parameter placeholders for later interpolation', 'title': 'Headers', 'type': 'object'}, 'body': {'additionalProperties': True, 'description': 'Dictionary of request body, with parameter placeholders for later interpolation', 'title': 'Body', 'type': 'object'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin', 'description': 'Credentials mode'}}, 'required': ['url', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\", 'properties': {'name': {'description': 'Parameter name (must be valid Python identifier)', 'title': 'Name', 'type': 'string'}, 'type': {'$ref': '#/$defs/ParameterType', 'default': 'string', 'description': 'Parameter data type'}, 'required': {'default': True, 'description': 'Whether parameter is required', 'title': 'Required', 'type': 'boolean'}, 'description': {'description': 'Human-readable parameter description', 'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{}, {'type': 'null'}], 'default': None, 'description': 'Default value if not provided', 'title': 'Default'}, 'examples': {'description': 'Example values', 'items': {}, 'title': 'Examples', 'type': 'array'}, 'min_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Minimum length for strings', 'title': 'Min Length'}, 'max_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Maximum length for strings', 'title': 'Max Length'}, 'min_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Minimum value for numbers', 'title': 'Min Value'}, 'max_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Maximum value for numbers', 'title': 'Max Value'}, 'pattern': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Regex pattern for string validation', 'title': 'Pattern'}, 'enum_values': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'default': None, 'description': 'Allowed values for enum type', 'title': 'Enum Values'}, 'format': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': \"Format specification (e.g., 'YYYY-MM-DD')\", 'title': 'Format'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'ParameterType': {'description': 'Supported parameter types for MCP tools.', 'enum': ['string', 'integer', 'number', 'boolean', 'date', 'datetime', 'email', 'url', 'enum'], 'title': 'ParameterType', 'type': 'string'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'id': {'description': 'Resource ID in format [resourceType]_[uuidv4]', 'title': 'Id', 'type': 'string'}, 'created_at': {'description': 'Unix timestamp (seconds) when resource was created', 'title': 'Created At', 'type': 'integer'}, 'updated_at': {'description': 'Unix timestamp (seconds) when resource was last updated', 'title': 'Updated At', 'type': 'integer'}, 'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'discriminator': {'mapping': {'fetch': '#/$defs/RoutineFetchOperation', 'navigate': '#/$defs/RoutineNavigateOperation', 'return': '#/$defs/RoutineReturnOperation', 'sleep': '#/$defs/RoutineSleepOperation'}, 'propertyName': 'type'}, 'oneOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'incognito': {'default': True, 'description': 'Whether to use incognito mode when executing the routine', 'title': 'Incognito', 'type': 'boolean'}, 'parameters': {'description': 'List of parameters', 'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations'], 'title': 'Routine', 'type': 'object'}Please respond in the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'description': 'Target API URL with parameter placeholders', 'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Human-readable description the fetch request', 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod', 'description': 'HTTP method'}, 'headers': {'additionalProperties': True, 'description': 'Dictionary of headers, with parameter placeholders for later interpolation', 'title': 'Headers', 'type': 'object'}, 'body': {'additionalProperties': True, 'description': 'Dictionary of request body, with parameter placeholders for later interpolation', 'title': 'Body', 'type': 'object'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin', 'description': 'Credentials mode'}}, 'required': ['url', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\", 'properties': {'name': {'description': 'Parameter name (must be valid Python identifier)', 'title': 'Name', 'type': 'string'}, 'type': {'$ref': '#/$defs/ParameterType', 'default': 'string', 'description': 'Parameter data type'}, 'required': {'default': True, 'description': 'Whether parameter is required', 'title': 'Required', 'type': 'boolean'}, 'description': {'description': 'Human-readable parameter description', 'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{}, {'type': 'null'}], 'default': None, 'description': 'Default value if not provided', 'title': 'Default'}, 'examples': {'description': 'Example values', 'items': {}, 'title': 'Examples', 'type': 'array'}, 'min_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Minimum length for strings', 'title': 'Min Length'}, 'max_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Maximum length for strings', 'title': 'Max Length'}, 'min_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Minimum value for numbers', 'title': 'Min Value'}, 'max_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Maximum value for numbers', 'title': 'Max Value'}, 'pattern': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Regex pattern for string validation', 'title': 'Pattern'}, 'enum_values': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'default': None, 'description': 'Allowed values for enum type', 'title': 'Enum Values'}, 'format': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': \"Format specification (e.g., 'YYYY-MM-DD')\", 'title': 'Format'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'ParameterType': {'description': 'Supported parameter types for MCP tools.', 'enum': ['string', 'integer', 'number', 'boolean', 'date', 'datetime', 'email', 'url', 'enum'], 'title': 'ParameterType', 'type': 'string'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'id': {'description': 'Resource ID in format [resourceType]_[uuidv4]', 'title': 'Id', 'type': 'string'}, 'created_at': {'description': 'Unix timestamp (seconds) when resource was created', 'title': 'Created At', 'type': 'integer'}, 'updated_at': {'description': 'Unix timestamp (seconds) when resource was last updated', 'title': 'Updated At', 'type': 'integer'}, 'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'discriminator': {'mapping': {'fetch': '#/$defs/RoutineFetchOperation', 'navigate': '#/$defs/RoutineNavigateOperation', 'return': '#/$defs/RoutineReturnOperation', 'sleep': '#/$defs/RoutineSleepOperation'}, 'propertyName': 'type'}, 'oneOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'incognito': {'default': True, 'description': 'Whether to use incognito mode when executing the routine', 'title': 'Incognito', 'type': 'boolean'}, 'parameters': {'description': 'List of parameters', 'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations'], 'title': 'Routine', 'type': 'object'}You immediate output needs to be a valid JSON object that conforms to the production routine schema." + }, + { + "role": "assistant", + "content": "{\n \"$defs\": {\n \"CREDENTIALS\": {\n \"description\": \"Supported credentials modes for API requests.\",\n \"enum\": [\n \"same-origin\",\n \"include\",\n \"omit\"\n ],\n \"title\": \"CREDENTIALS\",\n \"type\": \"string\"\n },\n \"Endpoint\": {\n \"description\": \"Endpoint model with comprehensive parameter validation.\",\n \"properties\": {\n \"url\": {\n \"description\": \"Target API URL with parameter placeholders\",\n \"title\": \"Url\",\n \"type\": \"string\"\n },\n \"description\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Human-readable description the fetch request\",\n \"title\": \"Description\"\n },\n \"method\": {\n \"$ref\": \"#/$defs/HTTPMethod\",\n \"description\": \"HTTP method\"\n },\n \"headers\": {\n \"additionalProperties\": true,\n \"description\": \"Dictionary of headers, with parameter placeholders for later interpolation\",\n \"title\": \"Headers\",\n \"type\": \"object\"\n },\n \"body\": {\n \"additionalProperties\": true,\n \"description\": \"Dictionary of request body, with parameter placeholders for later interpolation\",\n \"title\": \"Body\",\n \"type\": \"object\"\n },\n \"credentials\": {\n \"$ref\": \"#/$defs/CREDENTIALS\",\n \"default\": \"same-origin\",\n \"description\": \"Credentials mode\"\n }\n },\n \"required\": [\n \"url\",\n \"method\",\n \"headers\",\n \"body\"\n ],\n \"title\": \"Endpoint\",\n \"type\": \"object\"\n },\n \"HTTPMethod\": {\n \"description\": \"Supported HTTP methods for API endpoints.\",\n \"enum\": [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"PATCH\"\n ],\n \"title\": \"HTTPMethod\",\n \"type\": \"string\"\n },\n \"Parameter\": {\n \"description\": \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\",\n \"properties\": {\n \"name\": {\n \"description\": \"Parameter name (must be valid Python identifier)\",\n \"title\": \"Name\",\n \"type\": \"string\"\n },\n \"type\": {\n \"$ref\": \"#/$defs/ParameterType\",\n \"default\": \"string\",\n \"description\": \"Parameter data type\"\n },\n \"required\": {\n \"default\": true,\n \"description\": \"Whether parameter is required\",\n \"title\": \"Required\",\n \"type\": \"boolean\"\n },\n \"description\": {\n \"description\": \"Human-readable parameter description\",\n \"title\": \"Description\",\n \"type\": \"string\"\n },\n \"default\": {\n \"anyOf\": [\n {},\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Default value if not provided\",\n \"title\": \"Default\"\n },\n \"examples\": {\n \"description\": \"Example values\",\n \"items\": {},\n \"title\": \"Examples\",\n \"type\": \"array\"\n },\n \"min_length\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Minimum length for strings\",\n \"title\": \"Min Length\"\n },\n \"max_length\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Maximum length for strings\",\n \"title\": \"Max Length\"\n },\n \"min_value\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"number\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Minimum value for numbers\",\n \"title\": \"Min Value\"\n },\n \"max_value\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"number\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Maximum value for numbers\",\n \"title\": \"Max Value\"\n },\n \"pattern\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Regex pattern for string validation\",\n \"title\": \"Pattern\"\n },\n \"enum_values\": {\n \"anyOf\": [\n {\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Allowed values for enum type\",\n \"title\": \"Enum Values\"\n },\n \"format\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Format specification (e.g., 'YYYY-MM-DD')\",\n \"title\": \"Format\"\n }\n },\n \"required\": [\n \"name\",\n \"description\"\n ],\n \"title\": \"Parameter\",\n \"type\": \"object\"\n },\n \"ParameterType\": {\n \"description\": \"Supported parameter types for MCP tools.\",\n \"enum\": [\n \"string\",\n \"integer\",\n \"number\",\n \"boolean\",\n \"date\",\n \"datetime\",\n \"email\",\n \"url\",\n \"enum\"\n ],\n \"title\": \"ParameterType\",\n \"type\": \"string\"\n },\n \"RoutineFetchOperation\": {\n \"description\": \"Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"fetch\",\n \"default\": \"fetch\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"endpoint\": {\n \"$ref\": \"#/$defs/Endpoint\"\n },\n \"session_storage_key\": {\n \"title\": \"Session Storage Key\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"endpoint\",\n \"session_storage_key\"\n ],\n \"title\": \"RoutineFetchOperation\",\n \"type\": \"object\"\n },\n \"RoutineNavigateOperation\": {\n \"description\": \"Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"navigate\",\n \"default\": \"navigate\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"url\": {\n \"title\": \"Url\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"url\"\n ],\n \"title\": \"RoutineNavigateOperation\",\n \"type\": \"object\"\n },\n \"RoutineReturnOperation\": {\n \"description\": \"Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"return\",\n \"default\": \"return\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"session_storage_key\": {\n \"title\": \"Session Storage Key\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"session_storage_key\"\n ],\n \"title\": \"RoutineReturnOperation\",\n \"type\": \"object\"\n },\n \"RoutineSleepOperation\": {\n \"description\": \"Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"sleep\",\n \"default\": \"sleep\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"timeout_seconds\": {\n \"title\": \"Timeout Seconds\",\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"timeout_seconds\"\n ],\n \"title\": \"RoutineSleepOperation\",\n \"type\": \"object\"\n }\n },\n \"name\": \"spirit_one_way_search\",\n \"description\": \"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.\",\n \"operations\": [\n {\n \"type\": \"navigate\",\n \"url\": \"https://www.spirit.com/\"\n },\n {\n \"type\": \"sleep\",\n \"timeout_seconds\": 2.5\n },\n {\n \"type\": \"fetch\",\n \"endpoint\": {\n \"url\": \"https://www.spirit.com/api/prod-token/api/v1/token\",\n \"description\": \"Issue a JWT used for Authorization: Bearer; response contains data.token.\",\n \"method\": \"POST\",\n \"headers\": {\n \"sec-ch-ua-platform\": \"\\\"macOS\\\"\",\n \"Cache-Control\": \"no-cache\",\n \"Referer\": \"https://www.spirit.com/\",\n \"Pragma\": \"no-cache\",\n \"Ocp-Apim-Subscription-Key\": \"3b6a6994753b4efc86376552e52b8432\",\n \"Accept\": \"application/json, text/plain, */*\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"\n },\n \"body\": {\n \"applicationName\": \"dotRezWeb\"\n },\n \"credentials\": \"same-origin\"\n },\n \"session_storage_key\": \"token_response\"\n },\n {\n \"type\": \"fetch\",\n \"endpoint\": {\n \"url\": \"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\n \"description\": \"One-way availability and prices for a single date (beginDate=endDate).\",\n \"method\": \"POST\",\n \"headers\": {\n \"sec-ch-ua-platform\": \"\\\"macOS\\\"\",\n \"Authorization\": \"Bearer {{sessionStorage:token_response.data.token}}\",\n \"Cache-Control\": \"no-cache\",\n \"Referer\": \"https://www.spirit.com/\",\n \"Accept-Language\": \"en-US\",\n \"Pragma\": \"no-cache\",\n \"Ocp-Apim-Subscription-Key\": \"3b6a6994753b4efc86376552e52b8432\",\n \"Accept\": \"application/json, text/plain, */*\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"\n },\n \"body\": {\n \"includeWifiAvailability\": true,\n \"criteria\": [\n {\n \"stations\": {\n \"originStationCodes\": [\n \"{{origin}}\"\n ],\n \"destinationStationCodes\": [\n \"{{destination}}\"\n ],\n \"searchDestinationMacs\": false\n },\n \"dates\": {\n \"beginDate\": \"{{date}}\",\n \"endDate\": \"{{date}}\"\n },\n \"filters\": {\n \"filter\": \"Default\"\n }\n }\n ],\n \"passengers\": {\n \"types\": [\n {\n \"type\": \"ADT\",\n \"count\": \"{{adt_count}}\"\n }\n ]\n },\n \"codes\": {\n \"currency\": \"{{currency}}\"\n },\n \"fareFilters\": {\n \"loyalty\": \"MonetaryOnly\",\n \"types\": [],\n \"classControl\": 1\n },\n \"taxesAndFees\": \"TaxesAndFees\",\n \"originalJourneyKeys\": [],\n \"originalBookingRecordLocator\": null,\n \"infantCount\": 0,\n \"birthDates\": [],\n \"includeBundleAvailability\": true\n },\n \"credentials\": \"same-origin\"\n },\n \"session_storage_key\": \"availability_search_response\"\n },\n {\n \"type\": \"return\",\n \"session_storage_key\": \"availability_search_response\"\n }\n ],\n \"incognito\": true,\n \"parameters\": [\n {\n \"name\": \"origin\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Origin IATA station code for the one-way search.\",\n \"default\": \"BOS\",\n \"examples\": [\n \"BOS\",\n \"LAX\",\n \"DTW\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n },\n {\n \"name\": \"destination\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Destination IATA station code for the one-way search.\",\n \"default\": \"MIA\",\n \"examples\": [\n \"MIA\",\n \"FLL\",\n \"LAS\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n },\n {\n \"name\": \"date\",\n \"type\": \"date\",\n \"required\": true,\n \"description\": \"Departure date. For one-way single-day search, beginDate=endDate=date.\",\n \"default\": \"2025-10-31\",\n \"examples\": [\n \"2025-10-31\",\n \"2025-11-15\"\n ],\n \"format\": \"YYYY-MM-DD\"\n },\n {\n \"name\": \"adt_count\",\n \"type\": \"integer\",\n \"required\": true,\n \"description\": \"Number of adult (ADT) passengers.\",\n \"default\": 1,\n \"examples\": [\n 1,\n 2\n ],\n \"min_value\": 1\n },\n {\n \"name\": \"currency\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Pricing currency code.\",\n \"default\": \"USD\",\n \"examples\": [\n \"USD\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n }\n ]\n}" + }, + { + "role": "user", + "content": "Write a dictionary of parameters to test this routine (from previous step): {\"id\":\"Routine_2c79b8f6-7d18-4854-a1b2-859bb184a344\",\"created_at\":1761882993,\"updated_at\":1761882993,\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue a JWT used for Authorization: Bearer; response contains data.token.\",\"method\":\"POST\",\"headers\":{\"sec-ch-ua-platform\":\"\\\"macOS\\\"\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"},\"body\":{\"applicationName\":\"dotRezWeb\"},\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for a single date (beginDate=endDate).\",\"method\":\"POST\",\"headers\":{\"sec-ch-ua-platform\":\"\\\"macOS\\\"\",\"Authorization\":\"Bearer {{sessionStorage:token_response.data.token}}\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Accept-Language\":\"en-US\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"},\"body\":{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"{{origin}}\"],\"destinationStationCodes\":[\"{{destination}}\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"{{date}}\",\"endDate\":\"{{date}}\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":\"{{adt_count}}\"}]},\"codes\":{\"currency\":\"{{currency}}\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true},\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"incognito\":true,\"parameters\":[{\"name\":\"origin\",\"type\":\"string\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null},{\"name\":\"destination\",\"type\":\"string\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null},{\"name\":\"date\",\"type\":\"date\",\"required\":true,\"description\":\"Departure date. For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"],\"min_length\":null,\"max_length\":null,\"min_value\":null,\"max_value\":null,\"pattern\":null,\"enum_values\":null,\"format\":\"YYYY-MM-DD\"},{\"name\":\"adt_count\",\"type\":\"integer\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":1,\"examples\":[1,2],\"min_length\":null,\"max_length\":null,\"min_value\":1,\"max_value\":null,\"pattern\":null,\"enum_values\":null,\"format\":null},{\"name\":\"currency\",\"type\":\"string\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null}]}Please respond in the following format: {'$defs': {'TestParameter': {'description': 'A test parameter for a routine.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'value': {'title': 'Value', 'type': 'string'}}, 'required': ['name', 'value'], 'title': 'TestParameter', 'type': 'object'}}, 'description': 'Response from the LLM for getting the test parameters for a routine.', 'properties': {'parameters': {'items': {'$ref': '#/$defs/TestParameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['parameters'], 'title': 'TestParametersResponse', 'type': 'object'}Ensure all parameters are present and have valid values." + }, + { + "role": "assistant", + "content": "{'$defs': {'TestParameter': {'description': 'A test parameter for a routine.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'value': {'title': 'Value', 'type': 'string'}}, 'required': ['name', 'value'], 'title': 'TestParameter', 'type': 'object'}}, 'description': 'Response from the LLM for getting the test parameters for a routine.', 'properties': {'parameters': {'items': {'$ref': '#/$defs/TestParameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['parameters'], 'title': 'TestParametersResponse', 'type': 'object', 'parameters': [{'name': 'origin', 'value': 'BOS'}, {'name': 'destination', 'value': 'MIA'}, {'name': 'date', 'value': '2025-10-31'}, {'name': 'adt_count', 'value': '1'}, {'name': 'currency', 'value': 'USD'}]}" + }, + { + "role": "assistant", + "content": "{\"parameters\":[{\"name\":\"origin\",\"value\":\"BOS\"},{\"name\":\"destination\",\"value\":\"MIA\"},{\"name\":\"date\",\"value\":\"2025-10-31\"},{\"name\":\"adt_count\",\"value\":\"1\"},{\"name\":\"currency\",\"value\":\"USD\"}]}" + } +] \ No newline at end of file diff --git a/routine_discovery_output_old/root_transaction.json b/routine_discovery_output_old/root_transaction.json new file mode 100644 index 0000000..0f37821 --- /dev/null +++ b/routine_discovery_output_old/root_transaction.json @@ -0,0 +1,8 @@ +{ + "transaction_id": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search", + "description": "Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.", + "url": "https://www.spirit.com/api/prod-availability/api/availability/v3/search", + "method": "POST", + "explanation": "This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .", + "confidence_level": "high" +} \ No newline at end of file diff --git a/routine_discovery_output_old/routine.json b/routine_discovery_output_old/routine.json new file mode 100644 index 0000000..85459c7 --- /dev/null +++ b/routine_discovery_output_old/routine.json @@ -0,0 +1,188 @@ +{ + "id": "Routine_2c79b8f6-7d18-4854-a1b2-859bb184a344", + "created_at": 1761882993, + "updated_at": 1761882993, + "name": "spirit_one_way_search", + "description": "Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.", + "operations": [ + { + "type": "navigate", + "url": "https://www.spirit.com/" + }, + { + "type": "sleep", + "timeout_seconds": 2.5 + }, + { + "type": "fetch", + "endpoint": { + "url": "https://www.spirit.com/api/prod-token/api/v1/token", + "description": "Issue a JWT used for Authorization: Bearer; response contains data.token.", + "method": "POST", + "headers": { + "sec-ch-ua-platform": "\"macOS\"", + "Cache-Control": "no-cache", + "Referer": "https://www.spirit.com/", + "Pragma": "no-cache", + "Ocp-Apim-Subscription-Key": "3b6a6994753b4efc86376552e52b8432", + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" + }, + "body": { + "applicationName": "dotRezWeb" + }, + "credentials": "same-origin" + }, + "session_storage_key": "token_response" + }, + { + "type": "fetch", + "endpoint": { + "url": "https://www.spirit.com/api/prod-availability/api/availability/v3/search", + "description": "One-way availability and prices for a single date (beginDate=endDate).", + "method": "POST", + "headers": { + "sec-ch-ua-platform": "\"macOS\"", + "Authorization": "Bearer \"{{sessionStorage:token_response.data.token}}\"", + "Cache-Control": "no-cache", + "Referer": "https://www.spirit.com/", + "Accept-Language": "en-US", + "Pragma": "no-cache", + "Ocp-Apim-Subscription-Key": "3b6a6994753b4efc86376552e52b8432", + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" + }, + "body": { + "includeWifiAvailability": true, + "criteria": [ + { + "stations": { + "originStationCodes": [ + "\"{{origin}}\"" + ], + "destinationStationCodes": [ + "\"{{destination}}\"" + ], + "searchDestinationMacs": false + }, + "dates": { + "beginDate": "\"{{date}}\"", + "endDate": "\"{{date}}\"" + }, + "filters": { + "filter": "Default" + } + } + ], + "passengers": { + "types": [ + { + "type": "ADT", + "count": "{{adt_count}}" + } + ] + }, + "codes": { + "currency": "USD" + }, + "fareFilters": { + "loyalty": "MonetaryOnly", + "types": [], + "classControl": 1 + }, + "taxesAndFees": "TaxesAndFees", + "originalJourneyKeys": [], + "originalBookingRecordLocator": null, + "infantCount": 0, + "birthDates": [], + "includeBundleAvailability": true + }, + "credentials": "same-origin" + }, + "session_storage_key": "availability_search_response" + }, + { + "type": "return", + "session_storage_key": "availability_search_response" + } + ], + "incognito": true, + "parameters": [ + { + "name": "origin", + "type": "string", + "required": true, + "description": "Origin IATA station code for the one-way search.", + "default": "BOS", + "examples": [ + "BOS", + "LAX", + "DTW" + ], + "min_length": 3, + "max_length": 3, + "min_value": null, + "max_value": null, + "pattern": "^[A-Z]{3}$", + "enum_values": null, + "format": null + }, + { + "name": "destination", + "type": "string", + "required": true, + "description": "Destination IATA station code for the one-way search.", + "default": "MIA", + "examples": [ + "MIA", + "FLL", + "LAS" + ], + "min_length": 3, + "max_length": 3, + "min_value": null, + "max_value": null, + "pattern": "^[A-Z]{3}$", + "enum_values": null, + "format": null + }, + { + "name": "date", + "type": "date", + "required": true, + "description": "Departure date. For one-way single-day search, beginDate=endDate=date.", + "default": "2025-10-31", + "examples": [ + "2025-10-31", + "2025-11-15" + ], + "min_length": null, + "max_length": null, + "min_value": null, + "max_value": null, + "pattern": null, + "enum_values": null, + "format": "YYYY-MM-DD" + }, + { + "name": "adt_count", + "type": "integer", + "required": true, + "description": "Number of adult (ADT) passengers.", + "default": 1, + "examples": [ + 1, + 2 + ], + "min_length": null, + "max_length": null, + "min_value": 1, + "max_value": null, + "pattern": null, + "enum_values": null, + "format": null + } + ] +} \ No newline at end of file diff --git a/routine_discovery_output_old/test_parameters.json b/routine_discovery_output_old/test_parameters.json new file mode 100644 index 0000000..91fb77c --- /dev/null +++ b/routine_discovery_output_old/test_parameters.json @@ -0,0 +1,7 @@ +{ + "origin": "BOS", + "destination": "MIA", + "date": "2025-11-26", + "adt_count": "1", + "currency": "USD" +} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_0/extracted_variables.json b/routine_discovery_output_old/transaction_0/extracted_variables.json new file mode 100644 index 0000000..293de5e --- /dev/null +++ b/routine_discovery_output_old/transaction_0/extracted_variables.json @@ -0,0 +1,212 @@ +{ + "transaction_id": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search", + "variables": [ + { + "type": "token", + "requires_resolution": true, + "name": "AuthorizationBearerToken", + "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", + "values_to_scan_for": [ + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + "eyJhbGciOiJSUzI1NiIsInR5cCI6Ik", + "KZYU5d88-7MUiPQ16Dt3", + "U1NJLjIifQ.bw8vxEnKZYU5d88", + "Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ" + ], + "description": "Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained." + }, + { + "type": "token", + "requires_resolution": false, + "name": "Ocp-Apim-Subscription-Key", + "observed_value": "3b6a6994753b4efc86376552e52b8432", + "values_to_scan_for": [ + "3b6a6994753b4efc86376552e52b8432", + "3b6a6994", + "52e52b8432" + ], + "description": "Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "originStationCode", + "observed_value": "BOS", + "values_to_scan_for": [ + "BOS" + ], + "description": "Origin IATA station code for one-way search." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "destinationStationCode", + "observed_value": "MIA", + "values_to_scan_for": [ + "MIA" + ], + "description": "Destination IATA station code for one-way search." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "beginDate", + "observed_value": "2025-10-31", + "values_to_scan_for": [ + "2025-10-31" + ], + "description": "Departure date (start of search window)." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "endDate", + "observed_value": "2025-10-31", + "values_to_scan_for": [ + "2025-10-31" + ], + "description": "Departure date (end of search window). Same as beginDate for one-way single-day search." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "searchDestinationMacs", + "observed_value": "false", + "values_to_scan_for": [ + "false" + ], + "description": "Flag in stations block; false in observed request." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "filters.filter", + "observed_value": "Default", + "values_to_scan_for": [ + "Default" + ], + "description": "Top-level criteria filter mode." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "passengerType", + "observed_value": "ADT", + "values_to_scan_for": [ + "ADT" + ], + "description": "Passenger type code (Adult)." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "passengerCount_ADT", + "observed_value": "1", + "values_to_scan_for": [ + "1" + ], + "description": "Number of adult passengers." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "currency", + "observed_value": "USD", + "values_to_scan_for": [ + "USD" + ], + "description": "Pricing currency for the search results." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "fareFilters.loyalty", + "observed_value": "MonetaryOnly", + "values_to_scan_for": [ + "MonetaryOnly" + ], + "description": "Fare loyalty filter used for pricing results." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "fareFilters.classControl", + "observed_value": "1", + "values_to_scan_for": [ + "1" + ], + "description": "Class control setting for fare filtering." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "taxesAndFees", + "observed_value": "TaxesAndFees", + "values_to_scan_for": [ + "TaxesAndFees" + ], + "description": "Specifies how taxes and fees are handled in pricing." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "infantCount", + "observed_value": "0", + "values_to_scan_for": [ + "0" + ], + "description": "Number of infants in the search." + }, + { + "type": "argument", + "requires_resolution": true, + "name": "birthDates", + "observed_value": "[]", + "values_to_scan_for": [ + "[]" + ], + "description": "Birthdates array for age-based pricing; empty in observed request." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "includeBundleAvailability", + "observed_value": "true", + "values_to_scan_for": [ + "true" + ], + "description": "Whether to include bundle availability in the search results." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "includeWifiAvailability", + "observed_value": "true", + "values_to_scan_for": [ + "true" + ], + "description": "Whether to include Wi-Fi availability in the search results." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "originalJourneyKeys", + "observed_value": "[]", + "values_to_scan_for": [ + "[]" + ], + "description": "Original journey keys (empty for new search)." + }, + { + "type": "argument", + "requires_resolution": false, + "name": "originalBookingRecordLocator", + "observed_value": "null", + "values_to_scan_for": [ + "null" + ], + "description": "Original booking record locator (null for new search)." + } + ], + "explanation": "Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions." +} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_0/resolved_variables.json b/routine_discovery_output_old/transaction_0/resolved_variables.json new file mode 100644 index 0000000..aed572a --- /dev/null +++ b/routine_discovery_output_old/transaction_0/resolved_variables.json @@ -0,0 +1,24 @@ +[ + { + "variable": { + "type": "token", + "requires_resolution": true, + "name": "AuthorizationBearerToken", + "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", + "values_to_scan_for": [ + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + "ZXhwIjoxNzYxODY0ODc2", + "KZYU5d88-7MUiPQ16Dt3", + "fV873-CYZMl9UjcstvK", + "QFhbk5JzA05OoZ4oGVfSNJ" + ], + "description": "Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired." + }, + "session_storage_source": null, + "transaction_source": { + "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token", + "dot_path": "token" + }, + "explanation": "The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches." + } +] \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_1/extracted_variables.json b/routine_discovery_output_old/transaction_1/extracted_variables.json new file mode 100644 index 0000000..b8879ab --- /dev/null +++ b/routine_discovery_output_old/transaction_1/extracted_variables.json @@ -0,0 +1,42 @@ +{ + "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token", + "variables": [ + { + "type": "argument", + "requires_resolution": false, + "name": "applicationName", + "observed_value": "dotRezWeb", + "values_to_scan_for": [ + "dotRezWeb" + ], + "description": "Application name sent in the token-issuance POST body." + }, + { + "type": "token", + "requires_resolution": false, + "name": "Ocp-Apim-Subscription-Key", + "observed_value": "3b6a6994753b4efc86376552e52b8432", + "values_to_scan_for": [ + "3b6a6994753b4efc86376552e52b8432", + "3b6a6994", + "52e52b8432" + ], + "description": "Subscription key required by Spirit APIs; typically static for the web app." + }, + { + "type": "token", + "requires_resolution": true, + "name": "AuthorizationBearerToken", + "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", + "values_to_scan_for": [ + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + "ZXhwIjoxNzYxODY0ODc2", + "KZYU5d88-7MUiPQ16Dt3", + "fV873-CYZMl9UjcstvK", + "QFhbk5JzA05OoZ4oGVfSNJ" + ], + "description": "JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired." + } + ], + "explanation": "The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs ." +} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_1/resolved_variables.json b/routine_discovery_output_old/transaction_1/resolved_variables.json new file mode 100644 index 0000000..2522516 --- /dev/null +++ b/routine_discovery_output_old/transaction_1/resolved_variables.json @@ -0,0 +1,24 @@ +[ + { + "variable": { + "type": "token", + "requires_resolution": true, + "name": "AuthorizationBearerToken", + "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", + "values_to_scan_for": [ + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + "ZXhwIjoxNzYxODY0ODc2", + "KZYU5d88-7MUiPQ16Dt3", + "fV873-CYZMl9UjcstvK", + "QFhbk5JzA05OoZ4oGVfSNJ" + ], + "description": "Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired." + }, + "session_storage_source": { + "type": "localStorage", + "dot_path": "token" + }, + "transaction_source": null, + "explanation": "The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\"token\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls." + } +] \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_2/extracted_variables.json b/routine_discovery_output_old/transaction_2/extracted_variables.json new file mode 100644 index 0000000..83e500d --- /dev/null +++ b/routine_discovery_output_old/transaction_2/extracted_variables.json @@ -0,0 +1,139 @@ +{ + "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token, 20251030_1761863992474_www.spirit.com_api_prod-token_api_v1_token", + "variables": [ + { + "type": "argument", + "requires_resolution": false, + "name": "applicationName", + "observed_value": "dotRezWeb", + "values_to_scan_for": [ + "dotRezWeb" + ], + "description": "JSON body field to request an API token from Spirit token service." + }, + { + "type": "token", + "requires_resolution": false, + "name": "Ocp-Apim-Subscription-Key", + "observed_value": "3b6a6994753b4efc86376552e52b8432", + "values_to_scan_for": [ + "3b6a6994753b4efc86376552e52b8432" + ], + "description": "Public APIM subscription key required on token and availability endpoints." + }, + { + "type": "token", + "requires_resolution": true, + "name": "Authorization", + "observed_value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", + "values_to_scan_for": [ + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + "eyJqdGkiOiIyZjNmZjM1NC05ZDVm" + ], + "description": "JWT Bearer used in Authorization header; must be obtained dynamically from token issuance." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "sec-ch-ua-platform", + "observed_value": "\"macOS\"", + "values_to_scan_for": [ + "\"macOS\"" + ], + "description": "Client hint platform header." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "sec-ch-ua", + "observed_value": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"", + "values_to_scan_for": [ + "\"Google Chrome\";v=\"141\"", + "\"Chromium\";v=\"141\"" + ], + "description": "Client hint brands header." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "sec-ch-ua-mobile", + "observed_value": "?0", + "values_to_scan_for": [ + "?0" + ], + "description": "Client hint mobile indicator." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "User-Agent", + "observed_value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", + "values_to_scan_for": [ + "Chrome/141.0.0.0", + "Safari/537.36" + ], + "description": "Browser User-Agent." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Accept", + "observed_value": "application/json, text/plain, */*", + "values_to_scan_for": [ + "application/json" + ], + "description": "Accept header for content negotiation." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Content-Type", + "observed_value": "application/json", + "values_to_scan_for": [ + "application/json" + ], + "description": "Content-Type header for JSON body." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Referer", + "observed_value": "https://www.spirit.com/", + "values_to_scan_for": [ + "https://www.spirit.com/" + ], + "description": "Referer header." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Cache-Control", + "observed_value": "no-cache", + "values_to_scan_for": [ + "no-cache" + ], + "description": "Cache-Control header." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Pragma", + "observed_value": "no-cache", + "values_to_scan_for": [ + "no-cache" + ], + "description": "Pragma header." + }, + { + "type": "browser_variable", + "requires_resolution": false, + "name": "Accept-Language", + "observed_value": "en-US", + "values_to_scan_for": [ + "en-US" + ], + "description": "Accept-Language header." + } + ], + "explanation": "Variables were extracted from the POST and GET requests to /api/prod-token/api/v1/token. The POST includes the JSON body { \"applicationName\": \"dotRezWeb\" } and the Ocp-Apim-Subscription-Key and browser headers in the request, as captured in the transaction record . The subsequent GET call to the same endpoint carries the Authorization: Bearer header alongside the same APIM key and browser headers, with its transaction and response captured as well ." +} \ No newline at end of file diff --git a/scripts/browser_monitor.py b/scripts/browser_monitor.py index 42c8743..fa37ced 100644 --- a/scripts/browser_monitor.py +++ b/scripts/browser_monitor.py @@ -210,11 +210,9 @@ def setup_output_directory(output_dir, keep_output): # Create organized subdirectories network_dir = os.path.join(output_dir, "network") storage_dir = os.path.join(output_dir, "storage") - interactions_dir = os.path.join(output_dir, "interactions") os.makedirs(network_dir, exist_ok=True) os.makedirs(storage_dir, exist_ok=True) - os.makedirs(interactions_dir, exist_ok=True) # Create transactions directory for unified request/response storage transactions_dir = os.path.join(network_dir, "transactions") @@ -224,16 +222,12 @@ def setup_output_directory(output_dir, keep_output): # Main directories 'network_dir': network_dir, 'storage_dir': storage_dir, - 'interactions_dir': interactions_dir, 'transactions_dir': transactions_dir, # Storage files 'storage_jsonl_path': os.path.join(storage_dir, "events.jsonl"), - # Interaction files - 'interactions_jsonl_path': os.path.join(interactions_dir, "events.jsonl"), - # Summary file 'summary_path': os.path.join(output_dir, "session_summary.json") } @@ -266,9 +260,6 @@ def save_session_summary(paths, summary, args, start_time, end_time, created_tab }, "storage": { "events": paths['storage_jsonl_path'] - }, - "interactions": { - "events": paths['interactions_jsonl_path'] } } } diff --git a/scripts/execute_routine.py b/scripts/execute_routine.py index 12f5e28..bee5a59 100644 --- a/scripts/execute_routine.py +++ b/scripts/execute_routine.py @@ -5,8 +5,8 @@ # Execute routine with parameters from a file python scripts/execute_routine.py \ - --routine-path routine_discovery_output/routine.json \ - --parameters-path routine_discovery_output/test_parameters.json + --routine-path example_routines/jetblue_one_way_flight_search.json \ + --parameters-path /Users/dimavremenko/Desktop/code/web-hacker/example_routines/jet_blue_input.json # Execute routine with parameters from a dictionary python scripts/execute_routine.py \ diff --git a/src/cdp/routine_execution.py b/src/cdp/routine_execution.py index 9a6d159..27e6a99 100644 --- a/src/cdp/routine_execution.py +++ b/src/cdp/routine_execution.py @@ -74,7 +74,20 @@ def _generate_fetch_js( " // Simple tokens (computed locally, no source lookup)", " function replaceSimpleTokens(str){", " if (typeof str !== 'string') return str;", - " str = str.replace(/\\{\\{\\s*epoch_milliseconds\\s*\\}\\}/ig, () => String(Date.now()));", + " // Handle quoted and unquoted: \"{{epoch_milliseconds}}\" or {{epoch_milliseconds}}", + " str = str.replace(/\\\"?\\{\\{\\s*epoch_milliseconds\\s*\\}\\}\\\"?/g, () => String(Date.now()));", + " // Handle {{uuid}} - generate UUID using crypto.randomUUID() if available", + " str = str.replace(/\\\"?\\{\\{\\s*uuid\\s*\\}\\}\\\"?/g, () => {", + " if ('randomUUID' in crypto) {", + " return crypto.randomUUID();", + " }", + " // Fallback for browsers without crypto.randomUUID()", + " return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {", + " const r = Math.random() * 16 | 0;", + " const v = c === 'x' ? r : (r & 0x3 | 0x8);", + " return v.toString(16);", + " });", + " });", " return str;", " }", "", @@ -113,7 +126,7 @@ def _generate_fetch_js( " }", " }", "", - " const PLACEHOLDER = /\\{\\{\\s*(sessionStorage|localStorage|cookie|meta)\\s*:\\s*([^}]+?)\\s*\\}\\}/g;", + " const PLACEHOLDER = /\\\"?\\{\\{\\s*(sessionStorage|localStorage|cookie|meta)\\s*:\\s*([^}]+?)\\s*\\}\\}\\\"?/g;", " function resolveOne(token){", " const [lhs, rhs] = token.split('||');", " const [kind, path] = lhs.split(':');", @@ -137,10 +150,22 @@ def _generate_fetch_js( " function resolvePlaceholders(str){", " if (typeof str !== 'string') return str;", " str = replaceSimpleTokens(str);", + " // Follow test.py pattern: for quoted placeholders, strings use raw value, objects use JSON.stringify", " return str.replace(PLACEHOLDER, (m, _k, inner) => {", " const v = resolveOne(`${_k}:${inner}`);", " if (v === undefined || v === null) return m;", - " return (typeof v === 'object') ? JSON.stringify(v) : String(v);", + " // Check if match was quoted - could be \"{{...}}\" or \\\"{{...}}\\\"", + " // Check for escaped quote \\\" at start/end, or simple quote \"", + " const startsWithEscaped = m.startsWith('\\\\\"') || m.startsWith('\"');", + " const endsWithEscaped = m.endsWith('\\\\\"') || (m.endsWith('\"') && m.length > 2);", + " const isQuoted = startsWithEscaped && endsWithEscaped;", + " if (isQuoted) {", + " // Quoted: strings use raw value (no quotes), objects use JSON.stringify", + " return (typeof v === 'string') ? v : JSON.stringify(v);", + " } else {", + " // Unquoted: always stringify", + " return (typeof v === 'object') ? JSON.stringify(v) : String(v);", + " }", " });", " }", "", @@ -344,7 +369,7 @@ def _execute_fetch_in_session( body_str = json.dumps(endpoint.body) # convert body from dict to str body_str_interpolated = _apply_params(body_str, parameters_dict) body = json.loads(body_str_interpolated) # convert body from str to dict - + # Prepare headers and body for injection hdrs = headers or {} @@ -402,6 +427,11 @@ def _apply_params(text: str, parameters_dict: dict | None) -> str: Only replaces {{param}} where 'param' is in parameters_dict. Leaves other placeholders like {{sessionStorage:...}} untouched. + + Follows the pattern from test.py: + - For string values in quoted placeholders: insert raw string (no quotes) + - For non-string values in quoted placeholders: use json.dumps(value) + - For unquoted placeholders: use str(value) Args: text: Text containing parameter placeholders. @@ -412,15 +442,33 @@ def _apply_params(text: str, parameters_dict: dict | None) -> str: """ if not text or not parameters_dict: return text - pattern = ( - r"\{\{\s*(" + "|".join(map(re.escape, parameters_dict.keys())) + r")\s*\}\}" - ) - - def repl(m): - key = m.group(1) - return str(parameters_dict.get(key, m.group(0))) - - return re.sub(pattern, repl, text) + + for key, value in parameters_dict.items(): + # Compute replacement based on value type (following test.py pattern) + if isinstance(value, str): + literal = value # For strings, insert raw string (no quotes) + else: + literal = json.dumps(value) # For numbers/bools/null, use JSON encoding + + escaped_key = re.escape(key) + + # Pattern 1: Simple quoted placeholder "{{key}}" in JSON string + # Matches: "{{key}}" (when the JSON value itself is the string "{{key}}") + # Use regular string concatenation to avoid f-string brace escaping issues + simple_quoted = '"' + r'\{\{' + r'\s*' + escaped_key + r'\s*' + r'\}\}' + '"' + text = re.sub(simple_quoted, literal, text) + + # Pattern 2: Escaped quote variant \"{{key}}\" + # In JSON string this appears as: \\"{{key}}\\" + # Use regular string concatenation to build pattern with proper escaping + double_escaped = r'\\"' + r'\{\{' + r'\s*' + escaped_key + r'\s*' + r'\}\}' + r'\\"' + text = re.sub(double_escaped, literal, text) + + # Pattern 3: Bare placeholder {{key}} (unquoted, for URL params, etc.) + bare_pattern = r'\{\{' + r'\s*' + escaped_key + r'\s*' + r'\}\}' + text = re.sub(bare_pattern, str(value), text) + + return text def _generate_random_user_agent() -> str: diff --git a/src/data_models/llm_responses.py b/src/data_models/llm_responses.py index 12e7012..5993161 100644 --- a/src/data_models/llm_responses.py +++ b/src/data_models/llm_responses.py @@ -12,7 +12,7 @@ class TransactionIdentificationResponse(BaseModel): Response from the LLM for identifying the network transaction that directly corresponds to the user's requested task. """ - transaction_id: str + transaction_id: str | None description: str url: str method: Method diff --git a/src/data_models/production_routine.py b/src/data_models/production_routine.py index 23f5fbf..19892ae 100644 --- a/src/data_models/production_routine.py +++ b/src/data_models/production_routine.py @@ -448,24 +448,27 @@ def validate_parameter_usage(self) -> 'Routine': # Extract all parameter names defined_parameters = {param.name for param in self.parameters} - # Find all parameter usages in the JSON: *{{*}}* - param_pattern = r'\{\{.*?\}\}' + # Find all parameter usages in the JSON: *"{{*}}"* + # Match quoted placeholders: "{{param}}" or \"{{param}}\" (escaped quotes in JSON strings) + # \"{{param}}\" in JSON string means "{{param}}" in actual value + # Pattern REQUIRES quotes (either " or \") immediately before {{ and after }} + param_pattern = r'(?:"|\\")\{\{([^}"]*)\}\}(?:"|\\")' matches = re.findall(param_pattern, routine_json) - + # track used parameters used_parameters = set() - + # iterate over all parameter usages for match in matches: - # clean the match from the {{ and }} - match = match.strip()[2:-2].strip() + # clean the match (already extracted the content between braces) + match = match.strip() # if the parameter name starts with a colon, it is a storage parameter if ":" in match: kind, path = [p.strip() for p in match.split(":", 1)] - assert kind in ["sessionStorage", "localStorage", "cookie"], f"Invalid prefix in parameter name: {kind}" - assert path, f"Path is required for sessionStorage, localStorage, and cookie: {kind}:{path}" + assert kind in ["sessionStorage", "localStorage", "cookie", "meta"], f"Invalid prefix in parameter name: {kind}" + assert path, f"Path is required for sessionStorage, localStorage, cookie, and meta: {kind}:{path}" continue # if the parameter name is a builtin parameter, add it to the used parameters elif match in builtin_parameter_names: @@ -490,5 +493,4 @@ def validate_parameter_usage(self) -> 'Routine': f"All parameters used in the routine must be defined in parameters." ) - return self - + return self \ No newline at end of file diff --git a/src/routine_discovery/agent.py b/src/routine_discovery/agent.py index 99f4116..e934d56 100644 --- a/src/routine_discovery/agent.py +++ b/src/routine_discovery/agent.py @@ -77,6 +77,9 @@ def run(self) -> None: # identify the transaction identified_transaction = self.identify_transaction() + if identified_transaction.transaction_id is None: + raise Exception("Failed to identify the network transactions that directly correspond to the user's requested task.") + # confirm the identified transaction confirmation_response = self.confirm_indetified_transaction(identified_transaction) @@ -115,7 +118,7 @@ def run(self) -> None: transaction = self.context_manager.get_transaction_by_id(transaction_id) # extract variables from the transaction - print("Extract variables (args, cookies, tokens, browser variables) from the identified transaction...") + print("Extracting variables (args, cookies, tokens, browser variables) from the identified transaction...") extracted_variables = self.extract_variables(transaction_id) # save the extracted variables @@ -134,13 +137,6 @@ def run(self) -> None: with open(save_path, "w") as f: json.dump(resolved_variables_json, f, ensure_ascii=False, indent=2) print(f"Resolved variables saved to: {save_path}") - - # adding transaction that need to be processed to the queue - for resolved_variable in resolved_variables: - if resolved_variable.transaction_source is not None: - new_transaction_id = resolved_variable.transaction_source.transaction_id - if new_transaction_id not in routine_transactions: - transaction_queue.append(new_transaction_id) # adding transaction data to the routine transactions routine_transactions[transaction_id] = { @@ -149,10 +145,15 @@ def run(self) -> None: "resolved_variables": [resolved_variable.model_dump() for resolved_variable in resolved_variables] } + # adding transaction that need to be processed to the queue + for resolved_variable in resolved_variables: + if resolved_variable.transaction_source is not None: + new_transaction_id = resolved_variable.transaction_source.transaction_id + if new_transaction_id not in routine_transactions: + transaction_queue.append(new_transaction_id) + # construct the routine routine = self.construct_routine(routine_transactions) - - print(f"Finalized routine construction! Routine saved to: {save_path}") # save the routine save_path = os.path.join(self.output_dir, f"routine.json") @@ -230,7 +231,7 @@ def identify_transaction(self) -> TransactionIdentificationResponse: # parse the response to the pydantic model parsed_response = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=TransactionIdentificationResponse, client=self.client, llm_model='gpt-5-nano' @@ -296,7 +297,7 @@ def confirm_indetified_transaction( # parse the response to the pydantic model parsed_response = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=TransactionConfirmationResponse, client=self.client, llm_model='gpt-5-nano' @@ -338,14 +339,14 @@ def extract_variables(self, transaction_id: str) -> ExtractedVariableResponse: transactions.append( { "request": transaction["request"], - "response": transaction["response"], - "response_body": response_body + # "response": transaction["response"], + # "response_body": response_body } ) # add message to the message history message = ( - f"Please extract the variables from the requests of identified network transactions: {transactions}" + f"Please extract the variables from only these network requests (requests only!): {transactions}" f"Please respond in the following format: {ExtractedVariableResponse.model_json_schema()}" "Mark each variable with requires_resolution=True if we need to dynamically resolve this variable at runtime." "If we can most likely hardcode this value, mark requires_resolution=False." @@ -378,7 +379,7 @@ def extract_variables(self, transaction_id: str) -> ExtractedVariableResponse: # parse the response to the pydantic model parsed_response = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=ExtractedVariableResponse, client=self.client, llm_model="gpt-5-nano" @@ -409,6 +410,8 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l # for each variable to resolve, try to find the source of the variable in the storage and transactions for variable in variables_to_resolve: + print(f"Resolving variable: {variable.name} with values to scan for: {variable.values_to_scan_for}") + # get the storage objects that contain the value and are before the latest timestamp storage_objects = [] for value in variable.values_to_scan_for: @@ -416,9 +419,12 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l value=value ) storage_sources.extend(storage_sources) + + if len(storage_sources) > 0: + print(f"Found {len(storage_sources)} storage sources that contain the value") # get the transaction ids that contain the value and are before the latest timestamp - transaction_ids = [] + transaction_ids = {} for value in variable.values_to_scan_for: transaction_ids.extend(self.context_manager.scan_transaction_responses( value=value, max_timestamp=max_timestamp @@ -426,6 +432,9 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l # deduplicate transaction ids transaction_ids = list(set(transaction_ids)) + + if len(transaction_ids) > 0: + print(f"Found {len(transaction_ids)} transaction ids that contain the value: {transaction_ids}") # add the transactions to the vectorstore uuid = str(uuid4()) @@ -445,6 +454,7 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l f"Dot paths should be like this: 'key.data.items[0].id', 'path.to.valiable.0.value', etc." f"For paths in transaction responses, start with the first key of the response body" f"For paths in storage, start with the cookie, local storage, or session storage entry name" + f"If the variable is found in both storage and transactions, you should indicate both sources and resolve them accordinly!" ) self._add_to_message_history("user", message) @@ -480,7 +490,7 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l # parse the response to the pydantic model parsed_response = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=ResolvedVariableResponse, client=self.client, llm_model="gpt-5-nano" @@ -509,7 +519,15 @@ def construct_routine(self, routine_transactions: dict, max_attempts: int = 3) - f"First step of the routine should be to navigate to the target web page and sleep for a bit of time (2-3 seconds). " f"All fetch operations should be constructed as follows: {RoutineFetchOperation.model_json_schema()}. " f"Parameters are only the most important arguments. " - f"You can inject variables by using the following syntax: {{{{parameter_name}}}} {{{{cookie:cookie_name}}}} {{{{sessionStorage:key.path.to.0.value}}}} {{{{local_storage:local_storage_name}}}}. " + f"You can inject variables by using placeholders. CRITICAL: PLACEHOLDERS ARE REPLACED AT RUNTIME AND THE RESULT MUST BE VALID JSON! " + f"For STRING values: Use \\\"{{{{parameter_name}}}}\\\" format (escaped quote + placeholder + escaped quote). " + f"Example: \\\"name\\\": \\\"\\\"{{{{user_name}}}}\\\"\\\". At runtime, \\\"\\\"{{{{user_name}}}}\\\"\\\" is replaced and becomes \\\"name\\\": \\\"John\\\" (valid JSON string). " + f"For NUMERIC values (int, float) or NULL: Use \\\"{{{{parameter_name}}}}\\\" format (regular quote + placeholder + quote). " + f"Example: \\\"amount\\\": \\\"{{{{price}}}}\\\". At runtime, \\\"{{{{price}}}}\\\" is replaced with the numeric value and quotes are removed, becoming \\\"amount\\\": 99.99 (JSON number, not string). " + f"Example: \\\"quantity\\\": \\\"{{{{count}}}}\\\" with value 5 becomes \\\"quantity\\\": 5 (JSON number). " + f"For NULL: \\\"metadata\\\": \\\"{{{{optional_field}}}}\\\" with null value becomes \\\"metadata\\\": null (JSON null). " + f"REMEMBER: After placeholder replacement, the JSON must be valid and parseable! " + f"Placeholder types: {{{{parameter_name}}}} for parameters, {{{{cookie:cookie_name}}}} for cookies, {{{{sessionStorage:key.path.to.0.value}}}} for session storage, {{{{localStorage:local_storage_name}}}} for local storage. " f"You can hardcode unresolved variables to their observed values. " f"You will want to navigate to the target page, then perform the fetch operations in the proper order. " f"Browser variables should be hardcoded to observed values. " @@ -547,7 +565,7 @@ def construct_routine(self, routine_transactions: dict, max_attempts: int = 3) - # parse the response to the pydantic model routine = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=Routine, client=self.client, llm_model=self.llm_model @@ -577,6 +595,18 @@ def productionize_routine(self, routine: Routine) -> Routine: f"You need to clean up this routine to follow the following format: {ProductionRoutine.model_json_schema()}" f"Please respond in the following format: {ProductionRoutine.model_json_schema()}" f"You immediate output needs to be a valid JSON object that conforms to the production routine schema." + f"CRITICAL: PLACEHOLDERS ARE REPLACED AT RUNTIME AND MUST RESULT IN VALID JSON! " + f"EXPLANATION: Placeholders like {{{{key}}}} are replaced at runtime with actual values. The format you choose determines the resulting JSON type. " + f"For STRING values: Use \\\"{{{{key}}}}\\\" format (escaped quote + placeholder + escaped quote). " + f"This means in the JSON file you write: \\\"\\\"{{{{user_name}}}}\\\"\\\". At runtime, the \\\"{{{{user_name}}}}\\\" part gets replaced, " + f"so \\\"\\\"{{{{user_name}}}}\\\"\\\" becomes \\\"\\\"John\\\"\\\" which becomes \\\"John\\\" (valid JSON string). " + f"For NUMERIC/NULL values: Use \\\"{{{{key}}}}\\\" format (regular quote + placeholder + quote). " + f"This means in the JSON file you write: \\\"{{{{item_id}}}}\\\". At runtime, the {{{{item_id}}}} part gets replaced with the number, " + f"and the surrounding quotes are removed, so \\\"{{{{item_id}}}}\\\" with value 42 becomes just 42 (valid JSON number, not string). " + f"Example: \\\"{{{{total_price}}}}\\\" with value 29.99 → becomes 29.99 (quotes removed, valid JSON number). " + f"Example: \\\"{{{{optional_data}}}}\\\" with null → becomes null (quotes removed, valid JSON null). " + """Placeholders will be resolved using this: param_pattern = r'(?:"|\\")\{\{([^}"]*)\}\}(?:"|\\")'""" + f"The resulting JSON MUST be valid and parseable after all placeholder replacements are done." ) self._add_to_message_history("user", message) @@ -596,9 +626,10 @@ def productionize_routine(self, routine: Routine) -> Routine: self._add_to_message_history("assistant", response_text) # parse the response to the pydantic model + # context includes the last 2 messages (user prompt + assistant response) to help with parsing production_routine = manual_llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=ProductionRoutine, client=self.client, llm_model=self.llm_model @@ -635,7 +666,7 @@ def get_test_parameters(self, routine: Routine) -> TestParametersResponse: # parse the response to the pydantic model parsed_response = llm_parse_text_to_model( text=response_text, - context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-3:]]), + context="\n".join([f"{msg['role']}: {msg['content']}" for msg in self.message_history[-2:]]), pydantic_model=TestParametersResponse, client=self.client, llm_model="gpt-5-nano" diff --git a/src/routine_discovery/context_manager.py b/src/routine_discovery/context_manager.py index eb88324..f578c1f 100644 --- a/src/routine_discovery/context_manager.py +++ b/src/routine_discovery/context_manager.py @@ -241,7 +241,8 @@ def scan_transaction_responses(self, value: str, max_timestamp: str | None = Non ) ): results.append(transaction_id) - return results + + return list(set(results)) def scan_storage_for_value(self, value: str, max_timestamp: str | None = None) -> list[str]: From 6c815cc25a47f857aa41fc9cdccf7666f524a85d Mon Sep 17 00:00:00 2001 From: Dima Vremekno Date: Sun, 2 Nov 2025 22:49:45 -0500 Subject: [PATCH 12/22] rm files --- ip_test_routine.json | 36 --- .../message_history.json | 114 ---------- .../root_transaction.json | 8 - routine_discovery_output_old/routine.json | 188 ---------------- .../test_parameters.json | 7 - .../transaction_0/extracted_variables.json | 212 ------------------ .../transaction_0/resolved_variables.json | 24 -- .../transaction_1/extracted_variables.json | 42 ---- .../transaction_1/resolved_variables.json | 24 -- .../transaction_2/extracted_variables.json | 139 ------------ src/data_models/production_routine.py | 2 +- 11 files changed, 1 insertion(+), 795 deletions(-) delete mode 100644 ip_test_routine.json delete mode 100644 routine_discovery_output_old/message_history.json delete mode 100644 routine_discovery_output_old/root_transaction.json delete mode 100644 routine_discovery_output_old/routine.json delete mode 100644 routine_discovery_output_old/test_parameters.json delete mode 100644 routine_discovery_output_old/transaction_0/extracted_variables.json delete mode 100644 routine_discovery_output_old/transaction_0/resolved_variables.json delete mode 100644 routine_discovery_output_old/transaction_1/extracted_variables.json delete mode 100644 routine_discovery_output_old/transaction_1/resolved_variables.json delete mode 100644 routine_discovery_output_old/transaction_2/extracted_variables.json diff --git a/ip_test_routine.json b/ip_test_routine.json deleted file mode 100644 index 2ba317f..0000000 --- a/ip_test_routine.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "id": "Routine_2f2859d3-3edf-4b13-ab7a-59ef06b6871c", - "created_at": 1761960892, - "updated_at": 1761960892, - "name": "ip_test", - "description": "Navigate to ipify.org and get the IP address.", - "operations": [ - { - "type": "navigate", - "url": "https://api.ipify.org/" - }, - { - "type": "sleep", - "timeout_seconds": 2.5 - }, - { - "type": "fetch", - "endpoint": { - "url": "https://api.ipify.org/", - "description": "Get IP address.", - "method": "GET", - "headers": {}, - "body": {}, - "credentials": "same-origin" - }, - "session_storage_key": "ip_address" - }, - { - "type": "return", - "session_storage_key": "ip_address" - } - ], - "incognito": true, - "parameters": [ - ] - } \ No newline at end of file diff --git a/routine_discovery_output_old/message_history.json b/routine_discovery_output_old/message_history.json deleted file mode 100644 index 36cdc38..0000000 --- a/routine_discovery_output_old/message_history.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "role": "system", - "content": "\n You are a helpful assistant that is an expert in parsing network traffic.\n You need to identify one or more network transactions that directly correspond to the user's requested task.\n You have access to vectorstore that contains network transactions and storage data\n (cookies, localStorage, sessionStorage, etc.).\n " - }, - { - "role": "user", - "content": "Task description: recover the spirit one way flight option and price api" - }, - { - "role": "user", - "content": "These are the possible network transaction ids you can choose from: ['20251030_1761863980617_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863968610_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863992134_www.spirit.com_api_prod-availability_api_availability_v2_lowfare', '20251030_1761863969444_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863968655_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863971857_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967634_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863977978_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863969655_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', '20251030_1761863970672_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863973741_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967901_content.spirit.com_api_content_en-US', '20251030_1761863973061_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863994486_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967911_content.spirit.com_api_content_en-US', '20251030_1761863978282_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863970591_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967972_p11.techlab-cdn.com_h_b90dea8b4dec42619841bf216443707a', '20251030_1761863969778_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_kG9DcwSi_SloPQVEoKw8_a0Q0Y_VpPBkhkAQ', '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', '20251030_1761863976683_www.spirit.com_api_prod-availability_api_Calendar_availableDates', '20251030_1761863967772_content.spirit.com_api_content_en-US', '20251030_1761863992676_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863992744_content.spirit.com_api_content_en-US', '20251030_1761863992683_www.spirit.com_assets_i18n_flight-search-widget_en-US.json', '20251030_1761863967890_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863992734_content.spirit.com_api_content_en-US', '20251030_1761863967894_www.spirit.com_assets_i18n_flight-search-widget_en-US.json', '20251030_1761863985315_www.spirit.com_3f-DnSRa1b_P2cN4Z_f2FL_iS9DcwSiJEOYb4_CjgEQVEoKw8_L3MfW_GoPA1A', '20251030_1761863967908_content.spirit.com_api_content_en-US', '20251030_1761863967669_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863997680_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863967886_www.spirit.com_api_prod-station_api_resources_v2_stations', '20251030_1761863968177_content.spirit.com_api_content_en-US', '20251030_1761863992750_content.spirit.com_api_content_en-US', '20251030_1761863967655_tzm.px-cloud.net_ns', '20251030_1761863992730_content.spirit.com_api_content_en-US', '20251030_1761863971827_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863992477_content.spirit.com_api_content_en-US', '20251030_1761863969842_bf04820crc.bf.dynatrace.com_bf', '20251030_1761863992480_www.spirit.com_assets_i18n_shared_en-US.json', '20251030_1761863967913_content.spirit.com_api_content_en-US', '20251030_1761863976688_www.spirit.com_api_prod-apo_api_apo', '20251030_1761863967898_content.spirit.com_api_content_en-US', '20251030_1761863992726_www.spirit.com_api_prod-station_api_resources_carriers', '20251030_1761863992474_www.spirit.com_api_prod-token_api_v1_token', '20251030_1761863991858_www.spirit.com_api_prod-booking_api_booking_reset', '20251030_1761863967905_content.spirit.com_api_content_en-US', '20251030_1761863988901_collector-pxkp4clsb5.px-cloud.net_api_v2_collector', '20251030_1761863992483_www.spirit.com_assets_i18n_book-path_en-US.json', '20251030_1761863992679_www.spirit.com_assets_i18n_flight_en-US.json']" - }, - { - "role": "user", - "content": "Please respond in the following format: {'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}, 'Method': {'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], 'title': 'Method', 'type': 'string'}}, 'description': \"Response from the LLM for identifying the network transaction that directly corresponds to\\nthe user's requested task. \", 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}, 'method': {'$ref': '#/$defs/Method'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['transaction_id', 'description', 'url', 'method', 'explanation', 'confidence_level'], 'title': 'TransactionIdentificationResponse', 'type': 'object'}" - }, - { - "role": "assistant", - "content": "{'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}, 'Method': {'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], 'title': 'Method', 'type': 'string'}}, 'description': \"Response from the LLM for identifying the network transaction that directly corresponds to\\nthe user's requested task. \", 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}, 'method': {'$ref': '#/$defs/Method'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['transaction_id', 'description', 'url', 'method', 'explanation', 'confidence_level'], 'title': 'TransactionIdentificationResponse', 'type': 'object', 'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'description': 'Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'explanation': 'This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .', 'confidence_level': 'high'}" - }, - { - "role": "assistant", - "content": "{\"transaction_id\":\"20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search\",\"description\":\"Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.\",\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"method\":\"POST\",\"explanation\":\"This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .\",\"confidence_level\":\"high\"}" - }, - { - "role": "user", - "content": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search have been added to the vectorstore in full (including response bodies).Please confirm that the identified transaction is correct and that it directly corresponds to the user's requested task:recover the spirit one way flight option and price apiPlease respond in the following format: {'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}}, 'description': \"Response obejct for confirming the identified network transactions that directly correspond to\\nthe user's requested task.\", 'properties': {'is_correct': {'title': 'Is Correct', 'type': 'boolean'}, 'confirmed_transaction_id': {'title': 'Confirmed Transaction Id', 'type': 'string'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['is_correct', 'confirmed_transaction_id', 'explanation', 'confidence_level'], 'title': 'TransactionConfirmationResponse', 'type': 'object'}" - }, - { - "role": "assistant", - "content": "{'$defs': {'ConfidenceLevel': {'enum': ['high', 'medium', 'low'], 'title': 'ConfidenceLevel', 'type': 'string'}}, 'description': \"Response obejct for confirming the identified network transactions that directly correspond to\\nthe user's requested task.\", 'properties': {'is_correct': {'title': 'Is Correct', 'type': 'boolean'}, 'confirmed_transaction_id': {'title': 'Confirmed Transaction Id', 'type': 'string'}, 'explanation': {'title': 'Explanation', 'type': 'string'}, 'confidence_level': {'$ref': '#/$defs/ConfidenceLevel'}}, 'required': ['is_correct', 'confirmed_transaction_id', 'explanation', 'confidence_level'], 'title': 'TransactionConfirmationResponse', 'type': 'object', 'is_correct': true, 'confirmed_transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'explanation': 'Yes. This POST to https://www.spirit.com/api/prod-availability/api/availability/v3/search contains a single-day search window (beginDate == endDate) with origin/destination and passenger details, which is Spirit’s one-way availability search that returns flight options and their prices.', 'confidence_level': 'high'}" - }, - { - "role": "user", - "content": "Please extract the variables from the requests of identified network transactions: [{'request': {'requestId': '5580.247', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"BOS\"],\"destinationStationCodes\":[\"MIA\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"2025-10-31\",\"endDate\":\"2025-10-31\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":1}]},\"codes\":{\"currency\":\"USD\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}}]Please respond in the following format: {'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object'}Mark each variable with requires_resolution=True if we need to dynamically resolve this variable at runtime.If we can most likely hardcode this value, mark requires_resolution=False.system variables are related to the device or browser environment, and are not used to identify the user.token and cookie values are not used to identify the user: these may need to be resolved at runtime.Only the actual values of the variables (token/cookies, etc.) should be placed into the observed_value field.The values of values_to_scan_for will then be used to scan the storage and transactions for the source of the variable so only include the actual values of the variables.values_to_scan_for should be possible substrings that will likely be present in the response body of a network transaction or a storage entry value.This is necessary to figure out where the variable is coming from." - }, - { - "role": "assistant", - "content": "{'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object', 'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'variables': [{'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'eyJhbGciOiJSUzI1NiIsInR5cCI6Ik', 'KZYU5d88-7MUiPQ16Dt3', 'U1NJLjIifQ.bw8vxEnKZYU5d88', 'Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ'], 'description': 'Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.'}, {'type': 'token', 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'originStationCode', 'observed_value': 'BOS', 'values_to_scan_for': ['BOS'], 'description': 'Origin IATA station code for one-way search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'destinationStationCode', 'observed_value': 'MIA', 'values_to_scan_for': ['MIA'], 'description': 'Destination IATA station code for one-way search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'beginDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (start of search window).'}, {'type': 'argument', 'requires_resolution': True, 'name': 'endDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (end of search window). Same as beginDate for one-way single-day search.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'searchDestinationMacs', 'observed_value': 'false', 'values_to_scan_for': ['false'], 'description': 'Flag in stations block; false in observed request.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'filters.filter', 'observed_value': 'Default', 'values_to_scan_for': ['Default'], 'description': 'Top-level criteria filter mode.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'passengerType', 'observed_value': 'ADT', 'values_to_scan_for': ['ADT'], 'description': 'Passenger type code (Adult).'}, {'type': 'argument', 'requires_resolution': True, 'name': 'passengerCount_ADT', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Number of adult passengers.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'currency', 'observed_value': 'USD', 'values_to_scan_for': ['USD'], 'description': 'Pricing currency for the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'fareFilters.loyalty', 'observed_value': 'MonetaryOnly', 'values_to_scan_for': ['MonetaryOnly'], 'description': 'Fare loyalty filter used for pricing results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'fareFilters.classControl', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Class control setting for fare filtering.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'taxesAndFees', 'observed_value': 'TaxesAndFees', 'values_to_scan_for': ['TaxesAndFees'], 'description': 'Specifies how taxes and fees are handled in pricing.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'infantCount', 'observed_value': '0', 'values_to_scan_for': ['0'], 'description': 'Number of infants in the search.'}, {'type': 'argument', 'requires_resolution': True, 'name': 'birthDates', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Birthdates array for age-based pricing; empty in observed request.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'includeBundleAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include bundle availability in the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'includeWifiAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include Wi-Fi availability in the search results.'}, {'type': 'argument', 'requires_resolution': False, 'name': 'originalJourneyKeys', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Original journey keys (empty for new search).'}, {'type': 'argument', 'requires_resolution': False, 'name': 'originalBookingRecordLocator', 'observed_value': 'null', 'values_to_scan_for': ['null'], 'description': 'Original booking record locator (null for new search).'}], 'explanation': 'Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.'}" - }, - { - "role": "assistant", - "content": "{\"transaction_id\":\"20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search\",\"variables\":[{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"eyJhbGciOiJSUzI1NiIsInR5cCI6Ik\",\"KZYU5d88-7MUiPQ16Dt3\",\"U1NJLjIifQ.bw8vxEnKZYU5d88\",\"Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ\"],\"description\":\"Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.\"},{\"type\":\"token\",\"requires_resolution\":false,\"name\":\"Ocp-Apim-Subscription-Key\",\"observed_value\":\"3b6a6994753b4efc86376552e52b8432\",\"values_to_scan_for\":[\"3b6a6994753b4efc86376552e52b8432\",\"3b6a6994\",\"52e52b8432\"],\"description\":\"Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"originStationCode\",\"observed_value\":\"BOS\",\"values_to_scan_for\":[\"BOS\"],\"description\":\"Origin IATA station code for one-way search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"destinationStationCode\",\"observed_value\":\"MIA\",\"values_to_scan_for\":[\"MIA\"],\"description\":\"Destination IATA station code for one-way search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"beginDate\",\"observed_value\":\"2025-10-31\",\"values_to_scan_for\":[\"2025-10-31\"],\"description\":\"Departure date (start of search window).\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"endDate\",\"observed_value\":\"2025-10-31\",\"values_to_scan_for\":[\"2025-10-31\"],\"description\":\"Departure date (end of search window). Same as beginDate for one-way single-day search.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"searchDestinationMacs\",\"observed_value\":\"false\",\"values_to_scan_for\":[\"false\"],\"description\":\"Flag in stations block; false in observed request.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"filters.filter\",\"observed_value\":\"Default\",\"values_to_scan_for\":[\"Default\"],\"description\":\"Top-level criteria filter mode.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"passengerType\",\"observed_value\":\"ADT\",\"values_to_scan_for\":[\"ADT\"],\"description\":\"Passenger type code (Adult).\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"passengerCount_ADT\",\"observed_value\":\"1\",\"values_to_scan_for\":[\"1\"],\"description\":\"Number of adult passengers.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"currency\",\"observed_value\":\"USD\",\"values_to_scan_for\":[\"USD\"],\"description\":\"Pricing currency for the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"fareFilters.loyalty\",\"observed_value\":\"MonetaryOnly\",\"values_to_scan_for\":[\"MonetaryOnly\"],\"description\":\"Fare loyalty filter used for pricing results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"fareFilters.classControl\",\"observed_value\":\"1\",\"values_to_scan_for\":[\"1\"],\"description\":\"Class control setting for fare filtering.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"taxesAndFees\",\"observed_value\":\"TaxesAndFees\",\"values_to_scan_for\":[\"TaxesAndFees\"],\"description\":\"Specifies how taxes and fees are handled in pricing.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"infantCount\",\"observed_value\":\"0\",\"values_to_scan_for\":[\"0\"],\"description\":\"Number of infants in the search.\"},{\"type\":\"argument\",\"requires_resolution\":true,\"name\":\"birthDates\",\"observed_value\":\"[]\",\"values_to_scan_for\":[\"[]\"],\"description\":\"Birthdates array for age-based pricing; empty in observed request.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"includeBundleAvailability\",\"observed_value\":\"true\",\"values_to_scan_for\":[\"true\"],\"description\":\"Whether to include bundle availability in the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"includeWifiAvailability\",\"observed_value\":\"true\",\"values_to_scan_for\":[\"true\"],\"description\":\"Whether to include Wi-Fi availability in the search results.\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"originalJourneyKeys\",\"observed_value\":\"[]\",\"values_to_scan_for\":[\"[]\"],\"description\":\"Original journey keys (empty for new search).\"},{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"originalBookingRecordLocator\",\"observed_value\":\"null\",\"values_to_scan_for\":[\"null\"],\"description\":\"Original booking record locator (null for new search).\"}],\"explanation\":\"Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.\"}" - }, - { - "role": "user", - "content": "Please resolve the variable: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJThe variable was found in the following storage sources: []The variable was found in the following transactions ids: ['20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token']These transactions are added to the vectorstore in full (including response bodies).Please respond in the following format: {'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object'}Dot paths should be like this: 'key.data.items[0].id', 'path.to.valiable.0.value', etc.For paths in transaction responses, start with the first key of the response bodyFor paths in storage, start with the cookie, local storage, or session storage entry name" - }, - { - "role": "assistant", - "content": "{'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object', 'variable': {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.'}, 'session_storage_source': None, 'transaction_source': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'dot_path': 'token'}, 'explanation': 'The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.'}" - }, - { - "role": "assistant", - "content": "{\"variable\":{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.\"},\"session_storage_source\":null,\"transaction_source\":{\"transaction_id\":\"20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token\",\"dot_path\":\"token\"},\"explanation\":\"The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.\"}" - }, - { - "role": "user", - "content": "Please extract the variables from the requests of identified network transactions: [{'request': {'requestId': '5580.235', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"applicationName\":\"dotRezWeb\"}'}}, {'request': {'requestId': '5580.288', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'GET', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}}}]Please respond in the following format: {'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object'}Mark each variable with requires_resolution=True if we need to dynamically resolve this variable at runtime.If we can most likely hardcode this value, mark requires_resolution=False.system variables are related to the device or browser environment, and are not used to identify the user.token and cookie values are not used to identify the user: these may need to be resolved at runtime.Only the actual values of the variables (token/cookies, etc.) should be placed into the observed_value field.The values of values_to_scan_for will then be used to scan the storage and transactions for the source of the variable so only include the actual values of the variables.values_to_scan_for should be possible substrings that will likely be present in the response body of a network transaction or a storage entry value.This is necessary to figure out where the variable is coming from." - }, - { - "role": "assistant", - "content": "{'$defs': {'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for extracting variables from the network transaction.', 'properties': {'transaction_id': {'title': 'Transaction Id', 'type': 'string'}, 'variables': {'items': {'$ref': '#/$defs/Variable'}, 'title': 'Variables', 'type': 'array'}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['transaction_id', 'variables', 'explanation'], 'title': 'ExtractedVariableResponse', 'type': 'object', 'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'variables': [{'type': 'argument', 'requires_resolution': False, 'name': 'applicationName', 'observed_value': 'dotRezWeb', 'values_to_scan_for': ['dotRezWeb'], 'description': 'Application name sent in the token-issuance POST body.'}, {'type': 'token', 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Subscription key required by Spirit APIs; typically static for the web app.'}, {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}], 'explanation': 'The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .'}" - }, - { - "role": "assistant", - "content": "{\"transaction_id\":\"20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token\",\"variables\":[{\"type\":\"argument\",\"requires_resolution\":false,\"name\":\"applicationName\",\"observed_value\":\"dotRezWeb\",\"values_to_scan_for\":[\"dotRezWeb\"],\"description\":\"Application name sent in the token-issuance POST body.\"},{\"type\":\"token\",\"requires_resolution\":false,\"name\":\"Ocp-Apim-Subscription-Key\",\"observed_value\":\"3b6a6994753b4efc86376552e52b8432\",\"values_to_scan_for\":[\"3b6a6994753b4efc86376552e52b8432\",\"3b6a6994\",\"52e52b8432\"],\"description\":\"Subscription key required by Spirit APIs; typically static for the web app.\"},{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.\"}],\"explanation\":\"The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .\"}" - }, - { - "role": "user", - "content": "Please resolve the variable: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJThe variable was found in the following storage sources: ['{\"type\": \"localStorageItemAdded\", \"origin\": \"https://www.spirit.com\", \"key\": \"token\", \"value\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\", \"timestamp\": 1761863976.68975}\\n', '{\"type\": \"localStorageItemAdded\", \"origin\": \"https://www.spirit.com\", \"key\": \"token\", \"value\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\", \"timestamp\": 1761863976.68975}\\n']The variable was found in the following transactions ids: []These transactions are added to the vectorstore in full (including response bodies).Please respond in the following format: {'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object'}Dot paths should be like this: 'key.data.items[0].id', 'path.to.valiable.0.value', etc.For paths in transaction responses, start with the first key of the response bodyFor paths in storage, start with the cookie, local storage, or session storage entry name" - }, - { - "role": "assistant", - "content": "{'$defs': {'SessionStorageSource': {'description': 'Source of the session storage.', 'properties': {'type': {'$ref': '#/$defs/SessionStorageType', 'description': 'The type of the session storage.'}, 'dot_path': {'description': 'The dot path to the variable in the session storage.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['type', 'dot_path'], 'title': 'SessionStorageSource', 'type': 'object'}, 'SessionStorageType': {'enum': ['cookie', 'localStorage', 'sessionStorage'], 'title': 'SessionStorageType', 'type': 'string'}, 'TransactionSource': {'description': 'Source of the transaction.', 'properties': {'transaction_id': {'description': 'The ID of the transaction that contains the variable.', 'title': 'Transaction Id', 'type': 'string'}, 'dot_path': {'description': 'The dot path to the variable in the transaction response body.', 'title': 'Dot Path', 'type': 'string'}}, 'required': ['transaction_id', 'dot_path'], 'title': 'TransactionSource', 'type': 'object'}, 'Variable': {'description': 'A variable that was extracted from the network transaction.', 'properties': {'type': {'$ref': '#/$defs/VariableType'}, 'requires_resolution': {'description': 'Whether the variable requires resolution.', 'title': 'Requires Resolution', 'type': 'boolean'}, 'name': {'title': 'Name', 'type': 'string'}, 'observed_value': {'title': 'Observed Value', 'type': 'string'}, 'values_to_scan_for': {'items': {'type': 'string'}, 'title': 'Values To Scan For', 'type': 'array'}, 'description': {'title': 'Description', 'type': 'string'}}, 'required': ['type', 'requires_resolution', 'name', 'observed_value', 'values_to_scan_for', 'description'], 'title': 'Variable', 'type': 'object'}, 'VariableType': {'enum': ['argument', 'cookie', 'token', 'browser_variable'], 'title': 'VariableType', 'type': 'string'}}, 'description': 'Response from the LLM for resolving cookies and tokens.', 'properties': {'variable': {'$ref': '#/$defs/Variable'}, 'session_storage_source': {'anyOf': [{'$ref': '#/$defs/SessionStorageSource'}, {'type': 'null'}], 'default': None}, 'transaction_source': {'anyOf': [{'$ref': '#/$defs/TransactionSource'}, {'type': 'null'}], 'default': None}, 'explanation': {'title': 'Explanation', 'type': 'string'}}, 'required': ['variable', 'explanation'], 'title': 'ResolvedVariableResponse', 'type': 'object', 'variable': {'type': 'token', 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize Spirit API requests; must be dynamically obtained and refreshed as it expires.'}, 'session_storage_source': {'type': 'localStorage', 'dot_path': 'token'}, 'transaction_source': None, 'explanation': 'The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\\\"token\\\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.'}" - }, - { - "role": "assistant", - "content": "{\"variable\":{\"type\":\"token\",\"requires_resolution\":true,\"name\":\"AuthorizationBearerToken\",\"observed_value\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ\",\"values_to_scan_for\":[\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\",\"ZXhwIjoxNzYxODY0ODc2\",\"KZYU5d88-7MUiPQ16Dt3\",\"fV873-CYZMl9UjcstvK\",\"QFhbk5JzA05OoZ4oGVfSNJ\"],\"description\":\"Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.\"},\"session_storage_source\":{\"type\":\"localStorage\",\"dot_path\":\"token\"},\"transaction_source\":null,\"explanation\":\"The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\\\"token\\\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.\"}" - }, - { - "role": "user", - "content": "Please construct the routine from the routine transactions: {'20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search': {'request': {'requestId': '5580.247', 'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Accept-Language': 'en-US', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"BOS\"],\"destinationStationCodes\":[\"MIA\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"2025-10-31\",\"endDate\":\"2025-10-31\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":1}]},\"codes\":{\"currency\":\"USD\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}, 'extracted_variables': {'transaction_id': '20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search', 'variables': [{'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'eyJhbGciOiJSUzI1NiIsInR5cCI6Ik', 'KZYU5d88-7MUiPQ16Dt3', 'U1NJLjIifQ.bw8vxEnKZYU5d88', 'Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ'], 'description': 'Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained.'}, {'type': , 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded.'}, {'type': , 'requires_resolution': True, 'name': 'originStationCode', 'observed_value': 'BOS', 'values_to_scan_for': ['BOS'], 'description': 'Origin IATA station code for one-way search.'}, {'type': , 'requires_resolution': True, 'name': 'destinationStationCode', 'observed_value': 'MIA', 'values_to_scan_for': ['MIA'], 'description': 'Destination IATA station code for one-way search.'}, {'type': , 'requires_resolution': True, 'name': 'beginDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (start of search window).'}, {'type': , 'requires_resolution': True, 'name': 'endDate', 'observed_value': '2025-10-31', 'values_to_scan_for': ['2025-10-31'], 'description': 'Departure date (end of search window). Same as beginDate for one-way single-day search.'}, {'type': , 'requires_resolution': False, 'name': 'searchDestinationMacs', 'observed_value': 'false', 'values_to_scan_for': ['false'], 'description': 'Flag in stations block; false in observed request.'}, {'type': , 'requires_resolution': False, 'name': 'filters.filter', 'observed_value': 'Default', 'values_to_scan_for': ['Default'], 'description': 'Top-level criteria filter mode.'}, {'type': , 'requires_resolution': True, 'name': 'passengerType', 'observed_value': 'ADT', 'values_to_scan_for': ['ADT'], 'description': 'Passenger type code (Adult).'}, {'type': , 'requires_resolution': True, 'name': 'passengerCount_ADT', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Number of adult passengers.'}, {'type': , 'requires_resolution': True, 'name': 'currency', 'observed_value': 'USD', 'values_to_scan_for': ['USD'], 'description': 'Pricing currency for the search results.'}, {'type': , 'requires_resolution': False, 'name': 'fareFilters.loyalty', 'observed_value': 'MonetaryOnly', 'values_to_scan_for': ['MonetaryOnly'], 'description': 'Fare loyalty filter used for pricing results.'}, {'type': , 'requires_resolution': False, 'name': 'fareFilters.classControl', 'observed_value': '1', 'values_to_scan_for': ['1'], 'description': 'Class control setting for fare filtering.'}, {'type': , 'requires_resolution': False, 'name': 'taxesAndFees', 'observed_value': 'TaxesAndFees', 'values_to_scan_for': ['TaxesAndFees'], 'description': 'Specifies how taxes and fees are handled in pricing.'}, {'type': , 'requires_resolution': True, 'name': 'infantCount', 'observed_value': '0', 'values_to_scan_for': ['0'], 'description': 'Number of infants in the search.'}, {'type': , 'requires_resolution': True, 'name': 'birthDates', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Birthdates array for age-based pricing; empty in observed request.'}, {'type': , 'requires_resolution': False, 'name': 'includeBundleAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include bundle availability in the search results.'}, {'type': , 'requires_resolution': False, 'name': 'includeWifiAvailability', 'observed_value': 'true', 'values_to_scan_for': ['true'], 'description': 'Whether to include Wi-Fi availability in the search results.'}, {'type': , 'requires_resolution': False, 'name': 'originalJourneyKeys', 'observed_value': '[]', 'values_to_scan_for': ['[]'], 'description': 'Original journey keys (empty for new search).'}, {'type': , 'requires_resolution': False, 'name': 'originalBookingRecordLocator', 'observed_value': 'null', 'values_to_scan_for': ['null'], 'description': 'Original booking record locator (null for new search).'}], 'explanation': 'Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions.'}, 'resolved_variables': [{'variable': {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired.'}, 'session_storage_source': None, 'transaction_source': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'dot_path': 'token'}, 'explanation': 'The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches.'}]}, '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token': {'request': {'requestId': '5580.235', 'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'method': 'POST', 'type': 'XHR', 'requestHeaders': {'sec-ch-ua-platform': '\"macOS\"', 'Cache-Control': 'no-cache', 'Referer': 'https://www.spirit.com/', 'Pragma': 'no-cache', 'sec-ch-ua': '\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"', 'sec-ch-ua-mobile': '?0', 'Ocp-Apim-Subscription-Key': '3b6a6994753b4efc86376552e52b8432', 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'}, 'postData': '{\"applicationName\":\"dotRezWeb\"}'}, 'extracted_variables': {'transaction_id': '20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token', 'variables': [{'type': , 'requires_resolution': False, 'name': 'applicationName', 'observed_value': 'dotRezWeb', 'values_to_scan_for': ['dotRezWeb'], 'description': 'Application name sent in the token-issuance POST body.'}, {'type': , 'requires_resolution': False, 'name': 'Ocp-Apim-Subscription-Key', 'observed_value': '3b6a6994753b4efc86376552e52b8432', 'values_to_scan_for': ['3b6a6994753b4efc86376552e52b8432', '3b6a6994', '52e52b8432'], 'description': 'Subscription key required by Spirit APIs; typically static for the web app.'}, {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}], 'explanation': 'The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs .'}, 'resolved_variables': [{'variable': {'type': , 'requires_resolution': True, 'name': 'AuthorizationBearerToken', 'observed_value': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ', 'values_to_scan_for': ['eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9', 'ZXhwIjoxNzYxODY0ODc2', 'KZYU5d88-7MUiPQ16Dt3', 'fV873-CYZMl9UjcstvK', 'QFhbk5JzA05OoZ4oGVfSNJ'], 'description': 'Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired.'}, 'session_storage_source': {'type': , 'dot_path': 'token'}, 'transaction_source': None, 'explanation': 'The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\"token\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls.'}]}}. Please respond in the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': 'Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (str | None): Default value if not provided\\n examples (list[str]): Example values', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'required': {'default': True, 'title': 'Required', 'type': 'boolean'}, 'description': {'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Default'}, 'examples': {'default': [], 'items': {'type': 'string'}, 'title': 'Examples', 'type': 'array'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'anyOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'parameters': {'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations', 'parameters'], 'title': 'Routine', 'type': 'object'}. Fetch operations (1 to 1 with transactions) should be constructed as follows: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}}, 'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}. First step of the routine should be to navigate to the target web page and sleep for a bit of time (2-3 seconds). All fetch operations should be constructed as follows: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}}, 'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}. Parameters are only the most important arguments. You can inject variables by using the following syntax: {{parameter_name}} {{cookie:cookie_name}} {{sessionStorage:key.path.to.0.value}} {{local_storage:local_storage_name}}. You can hardcode unresolved variables to their observed values. You will want to navigate to the target page, then perform the fetch operations in the proper order. Browser variables should be hardcoded to observed values. If tokens or cookies are resolved, they should point to values in the session storage.You can navigate to other pages in the routine by using the navigate operation. Endpoints of the fetch operations should mimick observed network traffic requests! Every fetch operation result is written to session storage. At the end of the routine return the proper session storage value (likely containing the last fetch operation result). To feed output of a fetch into a subsequent fetch, you can save result to session storage and then use {sessionStorage:key.to.path}. " - }, - { - "role": "assistant", - "content": "{'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod'}, 'headers': {'title': 'Headers', 'type': 'string'}, 'body': {'title': 'Body', 'type': 'string'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin'}}, 'required': ['url', 'description', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': 'Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (str | None): Default value if not provided\\n examples (list[str]): Example values', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'required': {'default': True, 'title': 'Required', 'type': 'boolean'}, 'description': {'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Default'}, 'examples': {'default': [], 'items': {'type': 'string'}, 'title': 'Examples', 'type': 'array'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'anyOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'parameters': {'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations', 'parameters'], 'title': 'Routine', 'type': 'object'}, 'name': 'spirit_one_way_search', 'description': 'Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .', 'operations': [{'type': 'navigate', 'url': 'https://www.spirit.com/'}, {'type': 'sleep', 'timeout_seconds': 2.5}, {'type': 'fetch', 'endpoint': {'url': 'https://www.spirit.com/api/prod-token/api/v1/token', 'description': 'Issue JWT used for Authorization: Bearer; response contains data.token per capture .', 'method': 'POST', 'headers': '{\"sec-ch-ua-platform\":\"\\\\\"macOS\\\\\"\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"}', 'body': '{\"applicationName\":\"dotRezWeb\"}'}, 'session_storage_key': 'token_response'}, {'type': 'fetch', 'endpoint': {'url': 'https://www.spirit.com/api/prod-availability/api/availability/v3/search', 'description': 'One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .', 'method': 'POST', 'headers': '{\"sec-ch-ua-platform\":\"\\\\\"macOS\\\\\"\",\"Authorization\":\"Bearer {{sessionStorage:token_response.data.token}}\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Accept-Language\":\"en-US\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"}', 'body': '{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"{{origin}}\"],\"destinationStationCodes\":[\"{{destination}}\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"{{date}}\",\"endDate\":\"{{date}}\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":{{adt_count}}}]}, \"codes\":{\"currency\":\"{{currency}}\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true}'}, 'session_storage_key': 'availability_search_response'}, {'type': 'return', 'session_storage_key': 'availability_search_response'}], 'parameters': [{'name': 'origin', 'description': 'Origin IATA station code for the one-way search.', 'default': 'BOS', 'examples': ['BOS', 'LAX', 'DTW']}, {'name': 'destination', 'description': 'Destination IATA station code for the one-way search.', 'default': 'MIA', 'examples': ['MIA', 'FLL', 'LAS']}, {'name': 'date', 'description': 'Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.', 'default': '2025-10-31', 'examples': ['2025-10-31', '2025-11-15']}, {'name': 'adt_count', 'description': 'Number of adult (ADT) passengers.', 'default': '1', 'examples': ['1', '2']}, {'name': 'currency', 'description': 'Pricing currency code.', 'default': 'USD', 'examples': ['USD']}] }" - }, - { - "role": "assistant", - "content": "{\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue JWT used for Authorization: Bearer; response contains data.token per capture .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"applicationName\\\":\\\"dotRezWeb\\\"}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Authorization\\\":\\\"Bearer {{sessionStorage:token_response.data.token}}\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Accept-Language\\\":\\\"en-US\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"includeWifiAvailability\\\":true,\\\"criteria\\\":[{\\\"stations\\\":{\\\"originStationCodes\\\":[\\\"{{origin}}\\\"],\\\"destinationStationCodes\\\":[\\\"{{destination}}\\\"],\\\"searchDestinationMacs\\\":false},\\\"dates\\\":{\\\"beginDate\\\":\\\"{{date}}\\\",\\\"endDate\\\":\\\"{{date}}\\\"},\\\"filters\\\":{\\\"filter\\\":\\\"Default\\\"}}],\\\"passengers\\\":{\\\"types\\\":[{\\\"type\\\":\\\"ADT\\\",\\\"count\\\":{{adt_count}}}]}, \\\"codes\\\":{\\\"currency\\\":\\\"{{currency}}\\\"},\\\"fareFilters\\\":{\\\"loyalty\\\":\\\"MonetaryOnly\\\",\\\"types\\\":[],\\\"classControl\\\":1},\\\"taxesAndFees\\\":\\\"TaxesAndFees\\\",\\\"originalJourneyKeys\\\":[],\\\"originalBookingRecordLocator\\\":null,\\\"infantCount\\\":0,\\\"birthDates\\\":[],\\\"includeBundleAvailability\\\":true}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"parameters\":[{\"name\":\"origin\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"]},{\"name\":\"destination\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"]},{\"name\":\"date\",\"required\":true,\"description\":\"Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"]},{\"name\":\"adt_count\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":\"1\",\"examples\":[\"1\",\"2\"]},{\"name\":\"currency\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"]}]}" - }, - { - "role": "user", - "content": "Please productionize the routine (from previosu step): {\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic (token POST, then availability v3 search) .\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue JWT used for Authorization: Bearer; response contains data.token per capture .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"applicationName\\\":\\\"dotRezWeb\\\"}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for BOS->MIA on a single date; mirrors captured request and headers .\",\"method\":\"POST\",\"headers\":\"{\\\"sec-ch-ua-platform\\\":\\\"\\\\\\\"macOS\\\\\\\"\\\",\\\"Authorization\\\":\\\"Bearer {{sessionStorage:token_response.data.token}}\\\",\\\"Cache-Control\\\":\\\"no-cache\\\",\\\"Referer\\\":\\\"https://www.spirit.com/\\\",\\\"Accept-Language\\\":\\\"en-US\\\",\\\"Pragma\\\":\\\"no-cache\\\",\\\"Ocp-Apim-Subscription-Key\\\":\\\"3b6a6994753b4efc86376552e52b8432\\\",\\\"Accept\\\":\\\"application/json, text/plain, */*\\\",\\\"Content-Type\\\":\\\"application/json\\\",\\\"User-Agent\\\":\\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\\\"}\",\"body\":\"{\\\"includeWifiAvailability\\\":true,\\\"criteria\\\":[{\\\"stations\\\":{\\\"originStationCodes\\\":[\\\"{{origin}}\\\"],\\\"destinationStationCodes\\\":[\\\"{{destination}}\\\"],\\\"searchDestinationMacs\\\":false},\\\"dates\\\":{\\\"beginDate\\\":\\\"{{date}}\\\",\\\"endDate\\\":\\\"{{date}}\\\"},\\\"filters\\\":{\\\"filter\\\":\\\"Default\\\"}}],\\\"passengers\\\":{\\\"types\\\":[{\\\"type\\\":\\\"ADT\\\",\\\"count\\\":{{adt_count}}}]}, \\\"codes\\\":{\\\"currency\\\":\\\"{{currency}}\\\"},\\\"fareFilters\\\":{\\\"loyalty\\\":\\\"MonetaryOnly\\\",\\\"types\\\":[],\\\"classControl\\\":1},\\\"taxesAndFees\\\":\\\"TaxesAndFees\\\",\\\"originalJourneyKeys\\\":[],\\\"originalBookingRecordLocator\\\":null,\\\"infantCount\\\":0,\\\"birthDates\\\":[],\\\"includeBundleAvailability\\\":true}\",\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"parameters\":[{\"name\":\"origin\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"]},{\"name\":\"destination\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"]},{\"name\":\"date\",\"required\":true,\"description\":\"Departure date (YYYY-MM-DD). For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"]},{\"name\":\"adt_count\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":\"1\",\"examples\":[\"1\",\"2\"]},{\"name\":\"currency\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"]}]}You need to clean up this routine to follow the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'description': 'Target API URL with parameter placeholders', 'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Human-readable description the fetch request', 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod', 'description': 'HTTP method'}, 'headers': {'additionalProperties': True, 'description': 'Dictionary of headers, with parameter placeholders for later interpolation', 'title': 'Headers', 'type': 'object'}, 'body': {'additionalProperties': True, 'description': 'Dictionary of request body, with parameter placeholders for later interpolation', 'title': 'Body', 'type': 'object'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin', 'description': 'Credentials mode'}}, 'required': ['url', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\", 'properties': {'name': {'description': 'Parameter name (must be valid Python identifier)', 'title': 'Name', 'type': 'string'}, 'type': {'$ref': '#/$defs/ParameterType', 'default': 'string', 'description': 'Parameter data type'}, 'required': {'default': True, 'description': 'Whether parameter is required', 'title': 'Required', 'type': 'boolean'}, 'description': {'description': 'Human-readable parameter description', 'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{}, {'type': 'null'}], 'default': None, 'description': 'Default value if not provided', 'title': 'Default'}, 'examples': {'description': 'Example values', 'items': {}, 'title': 'Examples', 'type': 'array'}, 'min_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Minimum length for strings', 'title': 'Min Length'}, 'max_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Maximum length for strings', 'title': 'Max Length'}, 'min_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Minimum value for numbers', 'title': 'Min Value'}, 'max_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Maximum value for numbers', 'title': 'Max Value'}, 'pattern': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Regex pattern for string validation', 'title': 'Pattern'}, 'enum_values': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'default': None, 'description': 'Allowed values for enum type', 'title': 'Enum Values'}, 'format': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': \"Format specification (e.g., 'YYYY-MM-DD')\", 'title': 'Format'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'ParameterType': {'description': 'Supported parameter types for MCP tools.', 'enum': ['string', 'integer', 'number', 'boolean', 'date', 'datetime', 'email', 'url', 'enum'], 'title': 'ParameterType', 'type': 'string'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'id': {'description': 'Resource ID in format [resourceType]_[uuidv4]', 'title': 'Id', 'type': 'string'}, 'created_at': {'description': 'Unix timestamp (seconds) when resource was created', 'title': 'Created At', 'type': 'integer'}, 'updated_at': {'description': 'Unix timestamp (seconds) when resource was last updated', 'title': 'Updated At', 'type': 'integer'}, 'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'discriminator': {'mapping': {'fetch': '#/$defs/RoutineFetchOperation', 'navigate': '#/$defs/RoutineNavigateOperation', 'return': '#/$defs/RoutineReturnOperation', 'sleep': '#/$defs/RoutineSleepOperation'}, 'propertyName': 'type'}, 'oneOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'incognito': {'default': True, 'description': 'Whether to use incognito mode when executing the routine', 'title': 'Incognito', 'type': 'boolean'}, 'parameters': {'description': 'List of parameters', 'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations'], 'title': 'Routine', 'type': 'object'}Please respond in the following format: {'$defs': {'CREDENTIALS': {'description': 'Supported credentials modes for API requests.', 'enum': ['same-origin', 'include', 'omit'], 'title': 'CREDENTIALS', 'type': 'string'}, 'Endpoint': {'description': 'Endpoint model with comprehensive parameter validation.', 'properties': {'url': {'description': 'Target API URL with parameter placeholders', 'title': 'Url', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Human-readable description the fetch request', 'title': 'Description'}, 'method': {'$ref': '#/$defs/HTTPMethod', 'description': 'HTTP method'}, 'headers': {'additionalProperties': True, 'description': 'Dictionary of headers, with parameter placeholders for later interpolation', 'title': 'Headers', 'type': 'object'}, 'body': {'additionalProperties': True, 'description': 'Dictionary of request body, with parameter placeholders for later interpolation', 'title': 'Body', 'type': 'object'}, 'credentials': {'$ref': '#/$defs/CREDENTIALS', 'default': 'same-origin', 'description': 'Credentials mode'}}, 'required': ['url', 'method', 'headers', 'body'], 'title': 'Endpoint', 'type': 'object'}, 'HTTPMethod': {'description': 'Supported HTTP methods for API endpoints.', 'enum': ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 'title': 'HTTPMethod', 'type': 'string'}, 'Parameter': {'description': \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\", 'properties': {'name': {'description': 'Parameter name (must be valid Python identifier)', 'title': 'Name', 'type': 'string'}, 'type': {'$ref': '#/$defs/ParameterType', 'default': 'string', 'description': 'Parameter data type'}, 'required': {'default': True, 'description': 'Whether parameter is required', 'title': 'Required', 'type': 'boolean'}, 'description': {'description': 'Human-readable parameter description', 'title': 'Description', 'type': 'string'}, 'default': {'anyOf': [{}, {'type': 'null'}], 'default': None, 'description': 'Default value if not provided', 'title': 'Default'}, 'examples': {'description': 'Example values', 'items': {}, 'title': 'Examples', 'type': 'array'}, 'min_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Minimum length for strings', 'title': 'Min Length'}, 'max_length': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None, 'description': 'Maximum length for strings', 'title': 'Max Length'}, 'min_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Minimum value for numbers', 'title': 'Min Value'}, 'max_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'null'}], 'default': None, 'description': 'Maximum value for numbers', 'title': 'Max Value'}, 'pattern': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Regex pattern for string validation', 'title': 'Pattern'}, 'enum_values': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'default': None, 'description': 'Allowed values for enum type', 'title': 'Enum Values'}, 'format': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': \"Format specification (e.g., 'YYYY-MM-DD')\", 'title': 'Format'}}, 'required': ['name', 'description'], 'title': 'Parameter', 'type': 'object'}, 'ParameterType': {'description': 'Supported parameter types for MCP tools.', 'enum': ['string', 'integer', 'number', 'boolean', 'date', 'datetime', 'email', 'url', 'enum'], 'title': 'ParameterType', 'type': 'string'}, 'RoutineFetchOperation': {'description': 'Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.', 'properties': {'type': {'const': 'fetch', 'default': 'fetch', 'title': 'Type', 'type': 'string'}, 'endpoint': {'$ref': '#/$defs/Endpoint'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['endpoint', 'session_storage_key'], 'title': 'RoutineFetchOperation', 'type': 'object'}, 'RoutineNavigateOperation': {'description': 'Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.', 'properties': {'type': {'const': 'navigate', 'default': 'navigate', 'title': 'Type', 'type': 'string'}, 'url': {'title': 'Url', 'type': 'string'}}, 'required': ['url'], 'title': 'RoutineNavigateOperation', 'type': 'object'}, 'RoutineReturnOperation': {'description': 'Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.', 'properties': {'type': {'const': 'return', 'default': 'return', 'title': 'Type', 'type': 'string'}, 'session_storage_key': {'title': 'Session Storage Key', 'type': 'string'}}, 'required': ['session_storage_key'], 'title': 'RoutineReturnOperation', 'type': 'object'}, 'RoutineSleepOperation': {'description': 'Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.', 'properties': {'type': {'const': 'sleep', 'default': 'sleep', 'title': 'Type', 'type': 'string'}, 'timeout_seconds': {'title': 'Timeout Seconds', 'type': 'number'}}, 'required': ['timeout_seconds'], 'title': 'RoutineSleepOperation', 'type': 'object'}}, 'description': 'Routine model with comprehensive parameter validation.', 'properties': {'id': {'description': 'Resource ID in format [resourceType]_[uuidv4]', 'title': 'Id', 'type': 'string'}, 'created_at': {'description': 'Unix timestamp (seconds) when resource was created', 'title': 'Created At', 'type': 'integer'}, 'updated_at': {'description': 'Unix timestamp (seconds) when resource was last updated', 'title': 'Updated At', 'type': 'integer'}, 'name': {'title': 'Name', 'type': 'string'}, 'description': {'title': 'Description', 'type': 'string'}, 'operations': {'items': {'discriminator': {'mapping': {'fetch': '#/$defs/RoutineFetchOperation', 'navigate': '#/$defs/RoutineNavigateOperation', 'return': '#/$defs/RoutineReturnOperation', 'sleep': '#/$defs/RoutineSleepOperation'}, 'propertyName': 'type'}, 'oneOf': [{'$ref': '#/$defs/RoutineNavigateOperation'}, {'$ref': '#/$defs/RoutineSleepOperation'}, {'$ref': '#/$defs/RoutineFetchOperation'}, {'$ref': '#/$defs/RoutineReturnOperation'}]}, 'title': 'Operations', 'type': 'array'}, 'incognito': {'default': True, 'description': 'Whether to use incognito mode when executing the routine', 'title': 'Incognito', 'type': 'boolean'}, 'parameters': {'description': 'List of parameters', 'items': {'$ref': '#/$defs/Parameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['name', 'description', 'operations'], 'title': 'Routine', 'type': 'object'}You immediate output needs to be a valid JSON object that conforms to the production routine schema." - }, - { - "role": "assistant", - "content": "{\n \"$defs\": {\n \"CREDENTIALS\": {\n \"description\": \"Supported credentials modes for API requests.\",\n \"enum\": [\n \"same-origin\",\n \"include\",\n \"omit\"\n ],\n \"title\": \"CREDENTIALS\",\n \"type\": \"string\"\n },\n \"Endpoint\": {\n \"description\": \"Endpoint model with comprehensive parameter validation.\",\n \"properties\": {\n \"url\": {\n \"description\": \"Target API URL with parameter placeholders\",\n \"title\": \"Url\",\n \"type\": \"string\"\n },\n \"description\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Human-readable description the fetch request\",\n \"title\": \"Description\"\n },\n \"method\": {\n \"$ref\": \"#/$defs/HTTPMethod\",\n \"description\": \"HTTP method\"\n },\n \"headers\": {\n \"additionalProperties\": true,\n \"description\": \"Dictionary of headers, with parameter placeholders for later interpolation\",\n \"title\": \"Headers\",\n \"type\": \"object\"\n },\n \"body\": {\n \"additionalProperties\": true,\n \"description\": \"Dictionary of request body, with parameter placeholders for later interpolation\",\n \"title\": \"Body\",\n \"type\": \"object\"\n },\n \"credentials\": {\n \"$ref\": \"#/$defs/CREDENTIALS\",\n \"default\": \"same-origin\",\n \"description\": \"Credentials mode\"\n }\n },\n \"required\": [\n \"url\",\n \"method\",\n \"headers\",\n \"body\"\n ],\n \"title\": \"Endpoint\",\n \"type\": \"object\"\n },\n \"HTTPMethod\": {\n \"description\": \"Supported HTTP methods for API endpoints.\",\n \"enum\": [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"PATCH\"\n ],\n \"title\": \"HTTPMethod\",\n \"type\": \"string\"\n },\n \"Parameter\": {\n \"description\": \"Parameter model with comprehensive validation and type information.\\n\\nFields:\\n name (str): Parameter name (must be valid Python identifier)\\n type (ParameterType): Parameter data type\\n required (bool): Whether parameter is required\\n description (str): Human-readable parameter description\\n default (Any | None): Default value if not provided\\n examples (list[Any]): Example values\\n min_length (int | None): Minimum length for strings\\n max_length (int | None): Maximum length for strings\\n min_value (int | float | None): Minimum value for numbers\\n max_value (int | float | None): Maximum value for numbers\\n pattern (str | None): Regex pattern for string validation\\n enum_values (list[str] | None): Allowed values for enum type\\n format (str | None): Format specification (e.g., 'YYYY-MM-DD')\",\n \"properties\": {\n \"name\": {\n \"description\": \"Parameter name (must be valid Python identifier)\",\n \"title\": \"Name\",\n \"type\": \"string\"\n },\n \"type\": {\n \"$ref\": \"#/$defs/ParameterType\",\n \"default\": \"string\",\n \"description\": \"Parameter data type\"\n },\n \"required\": {\n \"default\": true,\n \"description\": \"Whether parameter is required\",\n \"title\": \"Required\",\n \"type\": \"boolean\"\n },\n \"description\": {\n \"description\": \"Human-readable parameter description\",\n \"title\": \"Description\",\n \"type\": \"string\"\n },\n \"default\": {\n \"anyOf\": [\n {},\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Default value if not provided\",\n \"title\": \"Default\"\n },\n \"examples\": {\n \"description\": \"Example values\",\n \"items\": {},\n \"title\": \"Examples\",\n \"type\": \"array\"\n },\n \"min_length\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Minimum length for strings\",\n \"title\": \"Min Length\"\n },\n \"max_length\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Maximum length for strings\",\n \"title\": \"Max Length\"\n },\n \"min_value\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"number\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Minimum value for numbers\",\n \"title\": \"Min Value\"\n },\n \"max_value\": {\n \"anyOf\": [\n {\n \"type\": \"integer\"\n },\n {\n \"type\": \"number\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Maximum value for numbers\",\n \"title\": \"Max Value\"\n },\n \"pattern\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Regex pattern for string validation\",\n \"title\": \"Pattern\"\n },\n \"enum_values\": {\n \"anyOf\": [\n {\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Allowed values for enum type\",\n \"title\": \"Enum Values\"\n },\n \"format\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"null\"\n }\n ],\n \"default\": null,\n \"description\": \"Format specification (e.g., 'YYYY-MM-DD')\",\n \"title\": \"Format\"\n }\n },\n \"required\": [\n \"name\",\n \"description\"\n ],\n \"title\": \"Parameter\",\n \"type\": \"object\"\n },\n \"ParameterType\": {\n \"description\": \"Supported parameter types for MCP tools.\",\n \"enum\": [\n \"string\",\n \"integer\",\n \"number\",\n \"boolean\",\n \"date\",\n \"datetime\",\n \"email\",\n \"url\",\n \"enum\"\n ],\n \"title\": \"ParameterType\",\n \"type\": \"string\"\n },\n \"RoutineFetchOperation\": {\n \"description\": \"Fetch operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.FETCH]): The type of operation.\\n endpoint (Endpoint): The endpoint to fetch.\\n session_storage_key (str | None): The session storage key to save the result to (optional).\\n\\nReturns:\\n RoutineFetchOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"fetch\",\n \"default\": \"fetch\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"endpoint\": {\n \"$ref\": \"#/$defs/Endpoint\"\n },\n \"session_storage_key\": {\n \"title\": \"Session Storage Key\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"endpoint\",\n \"session_storage_key\"\n ],\n \"title\": \"RoutineFetchOperation\",\n \"type\": \"object\"\n },\n \"RoutineNavigateOperation\": {\n \"description\": \"Navigate operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.NAVIGATE]): The type of operation.\\n url (str): The URL to navigate to.\\n\\nReturns:\\n RoutineNavigateOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"navigate\",\n \"default\": \"navigate\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"url\": {\n \"title\": \"Url\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"url\"\n ],\n \"title\": \"RoutineNavigateOperation\",\n \"type\": \"object\"\n },\n \"RoutineReturnOperation\": {\n \"description\": \"Return operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.RETURN]): The type of operation.\\n session_storage_key (str): The session storage key to return.\\n\\nReturns:\\n RoutineReturnOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"return\",\n \"default\": \"return\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"session_storage_key\": {\n \"title\": \"Session Storage Key\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"session_storage_key\"\n ],\n \"title\": \"RoutineReturnOperation\",\n \"type\": \"object\"\n },\n \"RoutineSleepOperation\": {\n \"description\": \"Sleep operation for routine.\\n\\nArgs:\\n type (Literal[RoutineOperationTypes.SLEEP]): The type of operation.\\n timeout_seconds (float): The number of seconds to sleep.\\n\\nReturns:\\n RoutineSleepOperation: The interpolated operation.\",\n \"properties\": {\n \"type\": {\n \"const\": \"sleep\",\n \"default\": \"sleep\",\n \"title\": \"Type\",\n \"type\": \"string\"\n },\n \"timeout_seconds\": {\n \"title\": \"Timeout Seconds\",\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"timeout_seconds\"\n ],\n \"title\": \"RoutineSleepOperation\",\n \"type\": \"object\"\n }\n },\n \"name\": \"spirit_one_way_search\",\n \"description\": \"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.\",\n \"operations\": [\n {\n \"type\": \"navigate\",\n \"url\": \"https://www.spirit.com/\"\n },\n {\n \"type\": \"sleep\",\n \"timeout_seconds\": 2.5\n },\n {\n \"type\": \"fetch\",\n \"endpoint\": {\n \"url\": \"https://www.spirit.com/api/prod-token/api/v1/token\",\n \"description\": \"Issue a JWT used for Authorization: Bearer; response contains data.token.\",\n \"method\": \"POST\",\n \"headers\": {\n \"sec-ch-ua-platform\": \"\\\"macOS\\\"\",\n \"Cache-Control\": \"no-cache\",\n \"Referer\": \"https://www.spirit.com/\",\n \"Pragma\": \"no-cache\",\n \"Ocp-Apim-Subscription-Key\": \"3b6a6994753b4efc86376552e52b8432\",\n \"Accept\": \"application/json, text/plain, */*\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"\n },\n \"body\": {\n \"applicationName\": \"dotRezWeb\"\n },\n \"credentials\": \"same-origin\"\n },\n \"session_storage_key\": \"token_response\"\n },\n {\n \"type\": \"fetch\",\n \"endpoint\": {\n \"url\": \"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\n \"description\": \"One-way availability and prices for a single date (beginDate=endDate).\",\n \"method\": \"POST\",\n \"headers\": {\n \"sec-ch-ua-platform\": \"\\\"macOS\\\"\",\n \"Authorization\": \"Bearer {{sessionStorage:token_response.data.token}}\",\n \"Cache-Control\": \"no-cache\",\n \"Referer\": \"https://www.spirit.com/\",\n \"Accept-Language\": \"en-US\",\n \"Pragma\": \"no-cache\",\n \"Ocp-Apim-Subscription-Key\": \"3b6a6994753b4efc86376552e52b8432\",\n \"Accept\": \"application/json, text/plain, */*\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"\n },\n \"body\": {\n \"includeWifiAvailability\": true,\n \"criteria\": [\n {\n \"stations\": {\n \"originStationCodes\": [\n \"{{origin}}\"\n ],\n \"destinationStationCodes\": [\n \"{{destination}}\"\n ],\n \"searchDestinationMacs\": false\n },\n \"dates\": {\n \"beginDate\": \"{{date}}\",\n \"endDate\": \"{{date}}\"\n },\n \"filters\": {\n \"filter\": \"Default\"\n }\n }\n ],\n \"passengers\": {\n \"types\": [\n {\n \"type\": \"ADT\",\n \"count\": \"{{adt_count}}\"\n }\n ]\n },\n \"codes\": {\n \"currency\": \"{{currency}}\"\n },\n \"fareFilters\": {\n \"loyalty\": \"MonetaryOnly\",\n \"types\": [],\n \"classControl\": 1\n },\n \"taxesAndFees\": \"TaxesAndFees\",\n \"originalJourneyKeys\": [],\n \"originalBookingRecordLocator\": null,\n \"infantCount\": 0,\n \"birthDates\": [],\n \"includeBundleAvailability\": true\n },\n \"credentials\": \"same-origin\"\n },\n \"session_storage_key\": \"availability_search_response\"\n },\n {\n \"type\": \"return\",\n \"session_storage_key\": \"availability_search_response\"\n }\n ],\n \"incognito\": true,\n \"parameters\": [\n {\n \"name\": \"origin\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Origin IATA station code for the one-way search.\",\n \"default\": \"BOS\",\n \"examples\": [\n \"BOS\",\n \"LAX\",\n \"DTW\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n },\n {\n \"name\": \"destination\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Destination IATA station code for the one-way search.\",\n \"default\": \"MIA\",\n \"examples\": [\n \"MIA\",\n \"FLL\",\n \"LAS\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n },\n {\n \"name\": \"date\",\n \"type\": \"date\",\n \"required\": true,\n \"description\": \"Departure date. For one-way single-day search, beginDate=endDate=date.\",\n \"default\": \"2025-10-31\",\n \"examples\": [\n \"2025-10-31\",\n \"2025-11-15\"\n ],\n \"format\": \"YYYY-MM-DD\"\n },\n {\n \"name\": \"adt_count\",\n \"type\": \"integer\",\n \"required\": true,\n \"description\": \"Number of adult (ADT) passengers.\",\n \"default\": 1,\n \"examples\": [\n 1,\n 2\n ],\n \"min_value\": 1\n },\n {\n \"name\": \"currency\",\n \"type\": \"string\",\n \"required\": true,\n \"description\": \"Pricing currency code.\",\n \"default\": \"USD\",\n \"examples\": [\n \"USD\"\n ],\n \"min_length\": 3,\n \"max_length\": 3,\n \"pattern\": \"^[A-Z]{3}$\"\n }\n ]\n}" - }, - { - "role": "user", - "content": "Write a dictionary of parameters to test this routine (from previous step): {\"id\":\"Routine_2c79b8f6-7d18-4854-a1b2-859bb184a344\",\"created_at\":1761882993,\"updated_at\":1761882993,\"name\":\"spirit_one_way_search\",\"description\":\"Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.\",\"operations\":[{\"type\":\"navigate\",\"url\":\"https://www.spirit.com/\"},{\"type\":\"sleep\",\"timeout_seconds\":2.5},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-token/api/v1/token\",\"description\":\"Issue a JWT used for Authorization: Bearer; response contains data.token.\",\"method\":\"POST\",\"headers\":{\"sec-ch-ua-platform\":\"\\\"macOS\\\"\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"},\"body\":{\"applicationName\":\"dotRezWeb\"},\"credentials\":\"same-origin\"},\"session_storage_key\":\"token_response\"},{\"type\":\"fetch\",\"endpoint\":{\"url\":\"https://www.spirit.com/api/prod-availability/api/availability/v3/search\",\"description\":\"One-way availability and prices for a single date (beginDate=endDate).\",\"method\":\"POST\",\"headers\":{\"sec-ch-ua-platform\":\"\\\"macOS\\\"\",\"Authorization\":\"Bearer {{sessionStorage:token_response.data.token}}\",\"Cache-Control\":\"no-cache\",\"Referer\":\"https://www.spirit.com/\",\"Accept-Language\":\"en-US\",\"Pragma\":\"no-cache\",\"Ocp-Apim-Subscription-Key\":\"3b6a6994753b4efc86376552e52b8432\",\"Accept\":\"application/json, text/plain, */*\",\"Content-Type\":\"application/json\",\"User-Agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36\"},\"body\":{\"includeWifiAvailability\":true,\"criteria\":[{\"stations\":{\"originStationCodes\":[\"{{origin}}\"],\"destinationStationCodes\":[\"{{destination}}\"],\"searchDestinationMacs\":false},\"dates\":{\"beginDate\":\"{{date}}\",\"endDate\":\"{{date}}\"},\"filters\":{\"filter\":\"Default\"}}],\"passengers\":{\"types\":[{\"type\":\"ADT\",\"count\":\"{{adt_count}}\"}]},\"codes\":{\"currency\":\"{{currency}}\"},\"fareFilters\":{\"loyalty\":\"MonetaryOnly\",\"types\":[],\"classControl\":1},\"taxesAndFees\":\"TaxesAndFees\",\"originalJourneyKeys\":[],\"originalBookingRecordLocator\":null,\"infantCount\":0,\"birthDates\":[],\"includeBundleAvailability\":true},\"credentials\":\"same-origin\"},\"session_storage_key\":\"availability_search_response\"},{\"type\":\"return\",\"session_storage_key\":\"availability_search_response\"}],\"incognito\":true,\"parameters\":[{\"name\":\"origin\",\"type\":\"string\",\"required\":true,\"description\":\"Origin IATA station code for the one-way search.\",\"default\":\"BOS\",\"examples\":[\"BOS\",\"LAX\",\"DTW\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null},{\"name\":\"destination\",\"type\":\"string\",\"required\":true,\"description\":\"Destination IATA station code for the one-way search.\",\"default\":\"MIA\",\"examples\":[\"MIA\",\"FLL\",\"LAS\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null},{\"name\":\"date\",\"type\":\"date\",\"required\":true,\"description\":\"Departure date. For one-way single-day search, beginDate=endDate=date.\",\"default\":\"2025-10-31\",\"examples\":[\"2025-10-31\",\"2025-11-15\"],\"min_length\":null,\"max_length\":null,\"min_value\":null,\"max_value\":null,\"pattern\":null,\"enum_values\":null,\"format\":\"YYYY-MM-DD\"},{\"name\":\"adt_count\",\"type\":\"integer\",\"required\":true,\"description\":\"Number of adult (ADT) passengers.\",\"default\":1,\"examples\":[1,2],\"min_length\":null,\"max_length\":null,\"min_value\":1,\"max_value\":null,\"pattern\":null,\"enum_values\":null,\"format\":null},{\"name\":\"currency\",\"type\":\"string\",\"required\":true,\"description\":\"Pricing currency code.\",\"default\":\"USD\",\"examples\":[\"USD\"],\"min_length\":3,\"max_length\":3,\"min_value\":null,\"max_value\":null,\"pattern\":\"^[A-Z]{3}$\",\"enum_values\":null,\"format\":null}]}Please respond in the following format: {'$defs': {'TestParameter': {'description': 'A test parameter for a routine.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'value': {'title': 'Value', 'type': 'string'}}, 'required': ['name', 'value'], 'title': 'TestParameter', 'type': 'object'}}, 'description': 'Response from the LLM for getting the test parameters for a routine.', 'properties': {'parameters': {'items': {'$ref': '#/$defs/TestParameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['parameters'], 'title': 'TestParametersResponse', 'type': 'object'}Ensure all parameters are present and have valid values." - }, - { - "role": "assistant", - "content": "{'$defs': {'TestParameter': {'description': 'A test parameter for a routine.', 'properties': {'name': {'title': 'Name', 'type': 'string'}, 'value': {'title': 'Value', 'type': 'string'}}, 'required': ['name', 'value'], 'title': 'TestParameter', 'type': 'object'}}, 'description': 'Response from the LLM for getting the test parameters for a routine.', 'properties': {'parameters': {'items': {'$ref': '#/$defs/TestParameter'}, 'title': 'Parameters', 'type': 'array'}}, 'required': ['parameters'], 'title': 'TestParametersResponse', 'type': 'object', 'parameters': [{'name': 'origin', 'value': 'BOS'}, {'name': 'destination', 'value': 'MIA'}, {'name': 'date', 'value': '2025-10-31'}, {'name': 'adt_count', 'value': '1'}, {'name': 'currency', 'value': 'USD'}]}" - }, - { - "role": "assistant", - "content": "{\"parameters\":[{\"name\":\"origin\",\"value\":\"BOS\"},{\"name\":\"destination\",\"value\":\"MIA\"},{\"name\":\"date\",\"value\":\"2025-10-31\"},{\"name\":\"adt_count\",\"value\":\"1\"},{\"name\":\"currency\",\"value\":\"USD\"}]}" - } -] \ No newline at end of file diff --git a/routine_discovery_output_old/root_transaction.json b/routine_discovery_output_old/root_transaction.json deleted file mode 100644 index 0f37821..0000000 --- a/routine_discovery_output_old/root_transaction.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "transaction_id": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search", - "description": "Spirit Airlines Availability v3 search endpoint returning one-way flight options and prices.", - "url": "https://www.spirit.com/api/prod-availability/api/availability/v3/search", - "method": "POST", - "explanation": "This POST to the availability v3 search endpoint includes a single-day date window (beginDate and endDate both 2025-10-31) with origin BOS, destination MIA, and 1 adult, which corresponds to a one-way availability query that returns flight options and pricing, as captured in the request payload and 200 response . A separate low-fare calendar endpoint exists (v2/lowfare) used for calendar fare ranges rather than listing flight options, which is why v3/search is the direct match for one-way options and prices .", - "confidence_level": "high" -} \ No newline at end of file diff --git a/routine_discovery_output_old/routine.json b/routine_discovery_output_old/routine.json deleted file mode 100644 index 85459c7..0000000 --- a/routine_discovery_output_old/routine.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "id": "Routine_2c79b8f6-7d18-4854-a1b2-859bb184a344", - "created_at": 1761882993, - "updated_at": 1761882993, - "name": "spirit_one_way_search", - "description": "Navigate to Spirit.com, obtain a bearer token, then call the availability v3 search API for one-way options and prices. The token is saved and injected into the Authorization header for the search call, mirroring observed traffic.", - "operations": [ - { - "type": "navigate", - "url": "https://www.spirit.com/" - }, - { - "type": "sleep", - "timeout_seconds": 2.5 - }, - { - "type": "fetch", - "endpoint": { - "url": "https://www.spirit.com/api/prod-token/api/v1/token", - "description": "Issue a JWT used for Authorization: Bearer; response contains data.token.", - "method": "POST", - "headers": { - "sec-ch-ua-platform": "\"macOS\"", - "Cache-Control": "no-cache", - "Referer": "https://www.spirit.com/", - "Pragma": "no-cache", - "Ocp-Apim-Subscription-Key": "3b6a6994753b4efc86376552e52b8432", - "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json", - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" - }, - "body": { - "applicationName": "dotRezWeb" - }, - "credentials": "same-origin" - }, - "session_storage_key": "token_response" - }, - { - "type": "fetch", - "endpoint": { - "url": "https://www.spirit.com/api/prod-availability/api/availability/v3/search", - "description": "One-way availability and prices for a single date (beginDate=endDate).", - "method": "POST", - "headers": { - "sec-ch-ua-platform": "\"macOS\"", - "Authorization": "Bearer \"{{sessionStorage:token_response.data.token}}\"", - "Cache-Control": "no-cache", - "Referer": "https://www.spirit.com/", - "Accept-Language": "en-US", - "Pragma": "no-cache", - "Ocp-Apim-Subscription-Key": "3b6a6994753b4efc86376552e52b8432", - "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json", - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" - }, - "body": { - "includeWifiAvailability": true, - "criteria": [ - { - "stations": { - "originStationCodes": [ - "\"{{origin}}\"" - ], - "destinationStationCodes": [ - "\"{{destination}}\"" - ], - "searchDestinationMacs": false - }, - "dates": { - "beginDate": "\"{{date}}\"", - "endDate": "\"{{date}}\"" - }, - "filters": { - "filter": "Default" - } - } - ], - "passengers": { - "types": [ - { - "type": "ADT", - "count": "{{adt_count}}" - } - ] - }, - "codes": { - "currency": "USD" - }, - "fareFilters": { - "loyalty": "MonetaryOnly", - "types": [], - "classControl": 1 - }, - "taxesAndFees": "TaxesAndFees", - "originalJourneyKeys": [], - "originalBookingRecordLocator": null, - "infantCount": 0, - "birthDates": [], - "includeBundleAvailability": true - }, - "credentials": "same-origin" - }, - "session_storage_key": "availability_search_response" - }, - { - "type": "return", - "session_storage_key": "availability_search_response" - } - ], - "incognito": true, - "parameters": [ - { - "name": "origin", - "type": "string", - "required": true, - "description": "Origin IATA station code for the one-way search.", - "default": "BOS", - "examples": [ - "BOS", - "LAX", - "DTW" - ], - "min_length": 3, - "max_length": 3, - "min_value": null, - "max_value": null, - "pattern": "^[A-Z]{3}$", - "enum_values": null, - "format": null - }, - { - "name": "destination", - "type": "string", - "required": true, - "description": "Destination IATA station code for the one-way search.", - "default": "MIA", - "examples": [ - "MIA", - "FLL", - "LAS" - ], - "min_length": 3, - "max_length": 3, - "min_value": null, - "max_value": null, - "pattern": "^[A-Z]{3}$", - "enum_values": null, - "format": null - }, - { - "name": "date", - "type": "date", - "required": true, - "description": "Departure date. For one-way single-day search, beginDate=endDate=date.", - "default": "2025-10-31", - "examples": [ - "2025-10-31", - "2025-11-15" - ], - "min_length": null, - "max_length": null, - "min_value": null, - "max_value": null, - "pattern": null, - "enum_values": null, - "format": "YYYY-MM-DD" - }, - { - "name": "adt_count", - "type": "integer", - "required": true, - "description": "Number of adult (ADT) passengers.", - "default": 1, - "examples": [ - 1, - 2 - ], - "min_length": null, - "max_length": null, - "min_value": 1, - "max_value": null, - "pattern": null, - "enum_values": null, - "format": null - } - ] -} \ No newline at end of file diff --git a/routine_discovery_output_old/test_parameters.json b/routine_discovery_output_old/test_parameters.json deleted file mode 100644 index 91fb77c..0000000 --- a/routine_discovery_output_old/test_parameters.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "origin": "BOS", - "destination": "MIA", - "date": "2025-11-26", - "adt_count": "1", - "currency": "USD" -} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_0/extracted_variables.json b/routine_discovery_output_old/transaction_0/extracted_variables.json deleted file mode 100644 index 293de5e..0000000 --- a/routine_discovery_output_old/transaction_0/extracted_variables.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "transaction_id": "20251030_1761863992142_www.spirit.com_api_prod-availability_api_availability_v3_search", - "variables": [ - { - "type": "token", - "requires_resolution": true, - "name": "AuthorizationBearerToken", - "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", - "values_to_scan_for": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", - "eyJhbGciOiJSUzI1NiIsInR5cCI6Ik", - "KZYU5d88-7MUiPQ16Dt3", - "U1NJLjIifQ.bw8vxEnKZYU5d88", - "Zm9ydmF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ" - ], - "description": "Bearer JWT used to authorize the availability search request. Expires and must be dynamically obtained." - }, - { - "type": "token", - "requires_resolution": false, - "name": "Ocp-Apim-Subscription-Key", - "observed_value": "3b6a6994753b4efc86376552e52b8432", - "values_to_scan_for": [ - "3b6a6994753b4efc86376552e52b8432", - "3b6a6994", - "52e52b8432" - ], - "description": "Public subscription key sent with Spirit APIs. Typically static for the web app; can often be hardcoded." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "originStationCode", - "observed_value": "BOS", - "values_to_scan_for": [ - "BOS" - ], - "description": "Origin IATA station code for one-way search." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "destinationStationCode", - "observed_value": "MIA", - "values_to_scan_for": [ - "MIA" - ], - "description": "Destination IATA station code for one-way search." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "beginDate", - "observed_value": "2025-10-31", - "values_to_scan_for": [ - "2025-10-31" - ], - "description": "Departure date (start of search window)." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "endDate", - "observed_value": "2025-10-31", - "values_to_scan_for": [ - "2025-10-31" - ], - "description": "Departure date (end of search window). Same as beginDate for one-way single-day search." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "searchDestinationMacs", - "observed_value": "false", - "values_to_scan_for": [ - "false" - ], - "description": "Flag in stations block; false in observed request." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "filters.filter", - "observed_value": "Default", - "values_to_scan_for": [ - "Default" - ], - "description": "Top-level criteria filter mode." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "passengerType", - "observed_value": "ADT", - "values_to_scan_for": [ - "ADT" - ], - "description": "Passenger type code (Adult)." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "passengerCount_ADT", - "observed_value": "1", - "values_to_scan_for": [ - "1" - ], - "description": "Number of adult passengers." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "currency", - "observed_value": "USD", - "values_to_scan_for": [ - "USD" - ], - "description": "Pricing currency for the search results." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "fareFilters.loyalty", - "observed_value": "MonetaryOnly", - "values_to_scan_for": [ - "MonetaryOnly" - ], - "description": "Fare loyalty filter used for pricing results." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "fareFilters.classControl", - "observed_value": "1", - "values_to_scan_for": [ - "1" - ], - "description": "Class control setting for fare filtering." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "taxesAndFees", - "observed_value": "TaxesAndFees", - "values_to_scan_for": [ - "TaxesAndFees" - ], - "description": "Specifies how taxes and fees are handled in pricing." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "infantCount", - "observed_value": "0", - "values_to_scan_for": [ - "0" - ], - "description": "Number of infants in the search." - }, - { - "type": "argument", - "requires_resolution": true, - "name": "birthDates", - "observed_value": "[]", - "values_to_scan_for": [ - "[]" - ], - "description": "Birthdates array for age-based pricing; empty in observed request." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "includeBundleAvailability", - "observed_value": "true", - "values_to_scan_for": [ - "true" - ], - "description": "Whether to include bundle availability in the search results." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "includeWifiAvailability", - "observed_value": "true", - "values_to_scan_for": [ - "true" - ], - "description": "Whether to include Wi-Fi availability in the search results." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "originalJourneyKeys", - "observed_value": "[]", - "values_to_scan_for": [ - "[]" - ], - "description": "Original journey keys (empty for new search)." - }, - { - "type": "argument", - "requires_resolution": false, - "name": "originalBookingRecordLocator", - "observed_value": "null", - "values_to_scan_for": [ - "null" - ], - "description": "Original booking record locator (null for new search)." - } - ], - "explanation": "Variables were extracted from the request headers and JSON body of the identified v3/search POST. Dynamic items like Authorization token, stations, dates, passenger counts, and currency are marked requires_resolution=True. Static flags and configuration-like values (e.g., subscription key, filter modes, includeBundleAvailability) are marked requires_resolution=False. values_to_scan_for include actual values or distinctive substrings to locate the sources of these variables in storage or other transactions." -} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_0/resolved_variables.json b/routine_discovery_output_old/transaction_0/resolved_variables.json deleted file mode 100644 index aed572a..0000000 --- a/routine_discovery_output_old/transaction_0/resolved_variables.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "variable": { - "type": "token", - "requires_resolution": true, - "name": "AuthorizationBearerToken", - "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", - "values_to_scan_for": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", - "ZXhwIjoxNzYxODY0ODc2", - "KZYU5d88-7MUiPQ16Dt3", - "fV873-CYZMl9UjcstvK", - "QFhbk5JzA05OoZ4oGVfSNJ" - ], - "description": "Bearer JWT used to authorize the availability search request. Must be dynamically obtained and refreshed when expired." - }, - "session_storage_source": null, - "transaction_source": { - "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token", - "dot_path": "token" - }, - "explanation": "The JWT is issued by the prod-token endpoint (transaction 20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token). Resolve it by calling this endpoint and reading the token field from the JSON response, then set it as the Authorization: Bearer header for subsequent availability searches." - } -] \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_1/extracted_variables.json b/routine_discovery_output_old/transaction_1/extracted_variables.json deleted file mode 100644 index b8879ab..0000000 --- a/routine_discovery_output_old/transaction_1/extracted_variables.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token", - "variables": [ - { - "type": "argument", - "requires_resolution": false, - "name": "applicationName", - "observed_value": "dotRezWeb", - "values_to_scan_for": [ - "dotRezWeb" - ], - "description": "Application name sent in the token-issuance POST body." - }, - { - "type": "token", - "requires_resolution": false, - "name": "Ocp-Apim-Subscription-Key", - "observed_value": "3b6a6994753b4efc86376552e52b8432", - "values_to_scan_for": [ - "3b6a6994753b4efc86376552e52b8432", - "3b6a6994", - "52e52b8432" - ], - "description": "Subscription key required by Spirit APIs; typically static for the web app." - }, - { - "type": "token", - "requires_resolution": true, - "name": "AuthorizationBearerToken", - "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", - "values_to_scan_for": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", - "ZXhwIjoxNzYxODY0ODc2", - "KZYU5d88-7MUiPQ16Dt3", - "fV873-CYZMl9UjcstvK", - "QFhbk5JzA05OoZ4oGVfSNJ" - ], - "description": "JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired." - } - ], - "explanation": "The prod-token POST includes applicationName=dotRezWeb in the JSON body and the Ocp-Apim-Subscription-Key header . The POST response returns the JWT at data.token, which is then used as the Authorization Bearer for subsequent requests, including the GET to the same endpoint and other APIs ." -} \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_1/resolved_variables.json b/routine_discovery_output_old/transaction_1/resolved_variables.json deleted file mode 100644 index 2522516..0000000 --- a/routine_discovery_output_old/transaction_1/resolved_variables.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "variable": { - "type": "token", - "requires_resolution": true, - "name": "AuthorizationBearerToken", - "observed_value": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", - "values_to_scan_for": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", - "ZXhwIjoxNzYxODY0ODc2", - "KZYU5d88-7MUiPQ16Dt3", - "fV873-CYZMl9UjcstvK", - "QFhbk5JzA05OoZ4oGVfSNJ" - ], - "description": "Bearer JWT used for Authorization: Bearer; must be dynamically obtained from the token service and refreshed when expired." - }, - "session_storage_source": { - "type": "localStorage", - "dot_path": "token" - }, - "transaction_source": null, - "explanation": "The JWT is stored in browser localStorage under the key token. Use localStorage.getItem(\"token\") to retrieve it at runtime and set it as the Authorization: Bearer header for subsequent API calls." - } -] \ No newline at end of file diff --git a/routine_discovery_output_old/transaction_2/extracted_variables.json b/routine_discovery_output_old/transaction_2/extracted_variables.json deleted file mode 100644 index 83e500d..0000000 --- a/routine_discovery_output_old/transaction_2/extracted_variables.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "transaction_id": "20251030_1761863976366_www.spirit.com_api_prod-token_api_v1_token, 20251030_1761863992474_www.spirit.com_api_prod-token_api_v1_token", - "variables": [ - { - "type": "argument", - "requires_resolution": false, - "name": "applicationName", - "observed_value": "dotRezWeb", - "values_to_scan_for": [ - "dotRezWeb" - ], - "description": "JSON body field to request an API token from Spirit token service." - }, - { - "type": "token", - "requires_resolution": false, - "name": "Ocp-Apim-Subscription-Key", - "observed_value": "3b6a6994753b4efc86376552e52b8432", - "values_to_scan_for": [ - "3b6a6994753b4efc86376552e52b8432" - ], - "description": "Public APIM subscription key required on token and availability endpoints." - }, - { - "type": "token", - "requires_resolution": true, - "name": "Authorization", - "observed_value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyZjNmZjM1NC05ZDVmLTRjNzAtYmE5OC1jNjU0ODViMjlmYzQiLCJhdXRoX3RpbWUiOiIxNzYxODYzOTc2Iiwic2Vzc2lvbklEIjoiMCIsInRva2VuVHlwZSI6IiIsImFnZW50SUQiOiI0MzY4NTUwNyIsImRvbWFpbkNvZGUiOiJXVzIiLCJhZ2VudE5hbWUiOiJ3ZWJhbm9ueW1vdXMyIiwib3JnYW5pemF0aW9uQ29kZSI6Ik5LIiwicm9sZUNvZGUiOiJXV1dBIiwiY2hhbm5lbFR5cGUiOiJEaWdpdGFsQVBJIiwic3lzdGVtVHlwZSI6IjExOSIsImNsaWVudE5hbWUiOiJkb3RSZXpXZWIiLCJjdWx0dXJlQ29kZSI6ImVuLVVTIiwiY3VycmVuY3lDb2RlIjoiVVNEIiwibG9jYXRpb25Db2RlIjoiU1lTIiwicGVyc29uSUQiOiI0MzY5NDM1NCIsInBlcnNvblR5cGUiOiIyIiwic3dpdGNoIjoiIiwidHJhY2VMZXZlbCI6IjAiLCJ0cmFjZVN3aXRjaGVzIjoiMCIsImFnZW50UXVldWVDb2RlIjoiIiwib3JnYW5pemF0aW9uUXVldWVDb2RlIjoiIiwiZXhwIjoxNzYxODY0ODc2fQ.bw8vxEnKZYU5d88-7MUiPQ16Dt34LEqD37m8QItetO8WMbywhqmjnh4gjf2GV2q2cznpMZ-wBuJhoA7DyyPIUCO4217lrMtRbCrPMnb6hxYUFfV873-CYZMl9UjcstvKLd779uzn3FpyTEME8gQw35kLzZ14NLRiogiOkCfLYEFSXNBaRPkxj2TU4IwYsRoQ-lwXQaa97emtjW7oOB-uWiSFSzAuntmGK9NEHjkkgskc63IeuAu-2m00b5JTNOzM5x2IyBBgF4jf4_iCIg54e5k0UVW_sai4LHqC9twuethvPkxRMNwwGJjKvfv2c8R7Yz-evVj0xFaKul_bHf1cYz12FhV2-BGQb5ByqAsFI1w1s7J_iu66Z9e_B7PTh9h1m51-Zm75xEQ2mq-ZX2SvrStlgTkLeLUM7wN1FeJ96SYjDSWmiOftcGeWwxjnVZl8caSHVXE7bSJUlG1M6COxzz7QPRLitfhmsJgx5BA8pMQFhbk5JzA05OoZ4oGVfSNJ", - "values_to_scan_for": [ - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", - "eyJqdGkiOiIyZjNmZjM1NC05ZDVm" - ], - "description": "JWT Bearer used in Authorization header; must be obtained dynamically from token issuance." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "sec-ch-ua-platform", - "observed_value": "\"macOS\"", - "values_to_scan_for": [ - "\"macOS\"" - ], - "description": "Client hint platform header." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "sec-ch-ua", - "observed_value": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"", - "values_to_scan_for": [ - "\"Google Chrome\";v=\"141\"", - "\"Chromium\";v=\"141\"" - ], - "description": "Client hint brands header." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "sec-ch-ua-mobile", - "observed_value": "?0", - "values_to_scan_for": [ - "?0" - ], - "description": "Client hint mobile indicator." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "User-Agent", - "observed_value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", - "values_to_scan_for": [ - "Chrome/141.0.0.0", - "Safari/537.36" - ], - "description": "Browser User-Agent." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Accept", - "observed_value": "application/json, text/plain, */*", - "values_to_scan_for": [ - "application/json" - ], - "description": "Accept header for content negotiation." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Content-Type", - "observed_value": "application/json", - "values_to_scan_for": [ - "application/json" - ], - "description": "Content-Type header for JSON body." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Referer", - "observed_value": "https://www.spirit.com/", - "values_to_scan_for": [ - "https://www.spirit.com/" - ], - "description": "Referer header." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Cache-Control", - "observed_value": "no-cache", - "values_to_scan_for": [ - "no-cache" - ], - "description": "Cache-Control header." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Pragma", - "observed_value": "no-cache", - "values_to_scan_for": [ - "no-cache" - ], - "description": "Pragma header." - }, - { - "type": "browser_variable", - "requires_resolution": false, - "name": "Accept-Language", - "observed_value": "en-US", - "values_to_scan_for": [ - "en-US" - ], - "description": "Accept-Language header." - } - ], - "explanation": "Variables were extracted from the POST and GET requests to /api/prod-token/api/v1/token. The POST includes the JSON body { \"applicationName\": \"dotRezWeb\" } and the Ocp-Apim-Subscription-Key and browser headers in the request, as captured in the transaction record . The subsequent GET call to the same endpoint carries the Authorization: Bearer header alongside the same APIM key and browser headers, with its transaction and response captured as well ." -} \ No newline at end of file diff --git a/src/data_models/production_routine.py b/src/data_models/production_routine.py index 19892ae..a226fd9 100644 --- a/src/data_models/production_routine.py +++ b/src/data_models/production_routine.py @@ -464,7 +464,7 @@ def validate_parameter_usage(self) -> 'Routine': # clean the match (already extracted the content between braces) match = match.strip() - # if the parameter name starts with a colon, it is a storage parameter + # if the parameter name contains a colon, it is a storage parameter if ":" in match: kind, path = [p.strip() for p in match.split(":", 1)] assert kind in ["sessionStorage", "localStorage", "cookie", "meta"], f"Invalid prefix in parameter name: {kind}" From 3d968a579115b1773f1fcea7d51399f32b920d75 Mon Sep 17 00:00:00 2001 From: Dima Vremekno Date: Sun, 2 Nov 2025 22:55:03 -0500 Subject: [PATCH 13/22] clean up old files --- example_routines/jet_blue_input.json | 6 - .../jetblue_one_way_flight_search.json | 111 ------------------ scripts/execute_routine.py | 4 +- 3 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 example_routines/jet_blue_input.json delete mode 100644 example_routines/jetblue_one_way_flight_search.json diff --git a/example_routines/jet_blue_input.json b/example_routines/jet_blue_input.json deleted file mode 100644 index 4baa44a..0000000 --- a/example_routines/jet_blue_input.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "origin": "BOS", - "destination": "JFK", - "date": "2026-01-15", - "adults": 1 -} \ No newline at end of file diff --git a/example_routines/jetblue_one_way_flight_search.json b/example_routines/jetblue_one_way_flight_search.json deleted file mode 100644 index 70437db..0000000 --- a/example_routines/jetblue_one_way_flight_search.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "routine_id": "550e8400-e29b-41d4-a716-446655440005", - "name": "jetblue_search_one_way", - "description": "Search for one-way flights on JetBlue. Use this when users want to find JetBlue flights for a specific route and date. Returns available itineraries with pricing, schedules, and booking options. Best for users who prefer JetBlue or want to compare with other airlines.", - "incognito": true, - "operations": [ - { - "type": "navigate", - "url": "https://www.jetblue.com/booking/cb-flights" - }, - { - "type": "sleep", - "timeout_seconds": 2 - }, - { - "type": "fetch", - "endpoint": { - "headers": { - "sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"", - "sec-ch-ua-mobile": "?0", - "Accept": "application/json, text/plain, */*", - "X-B3-SpanId": "{{uuid}}", - "ocp-apim-subscription-key": "{{localStorage:jb-app-config-original.crystalBlueSubscriptionKey}}", - "sec-ch-ua-platform": "\"macOS\"", - "Referer": "https://www.jetblue.com", - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", - "X-B3-TraceId": "{{epoch_milliseconds}}", - "Content-Type": "application/json" - }, - "method": "POST", - "body": { - "awardBooking": false, - "searchComponents": [ - { - "date": "\"{{date}}\"", - "from": "\"{{origin}}\"", - "to": "\"{{destination}}\"" - } - ], - "travelerTypes": [ - { - "type": "ADULT", - "quantity": "{{adults}}" - } - ] - }, - "url": "https://cb-api.jetblue.com/cb-flight-search/v1/search/NGB?digb_enable_cb_profile=true&crystal_blue_price_summary=true&crystal_blue_seats_extras=true&digb_acfp_previewseatmap=true&digb_acfp_opsseatmap=true&is_cb_flow=true" - }, - "session_storage_key": "jetblue_search_one_way_result" - }, - { - "type": "return", - "session_storage_key": "jetblue_search_one_way_result" - } -], - "parameters": [ - { - "name": "adults", - "description": "Number of adult travelers (1-9). Defaults to 1 for single traveler searches. For group bookings, specify the total number of adults.", - "default": 1, - "type": "integer", - "examples": [ - 1, - 2, - 4 - ], - "required": true - }, - { - "name": "origin", - "description": "Origin airport IATA code (3-letter code like BOS, JFK, LAX). Use airport codes, not city names. For major cities, use the primary airport code.", - "default": "BOS", - "type": "string", - "examples": [ - "BOS", - "JFK", - "LAX", - "SFO", - "FLL" - ], - "required": true - }, - { - "name": "destination", - "description": "Destination airport IATA code (3-letter code like SFO, JFK, LAX). Use airport codes, not city names. For major cities, use the primary airport code.", - "default": "SFO", - "type": "string", - "examples": [ - "SFO", - "JFK", - "BOS", - "LAX", - "FLL" - ], - "required": true - }, - { - "default": "2025-11-13", - "examples": [ - "2025-11-13", - "2025-12-01", - "2026-01-15" - ], - "name": "date", - "format": "YYYY-MM-DD", - "description": "Departure date in YYYY-MM-DD format. Use future dates only. For best results, search 1-6 months in advance.", - "type": "date", - "required": true - } - ] - } \ No newline at end of file diff --git a/scripts/execute_routine.py b/scripts/execute_routine.py index bee5a59..12f5e28 100644 --- a/scripts/execute_routine.py +++ b/scripts/execute_routine.py @@ -5,8 +5,8 @@ # Execute routine with parameters from a file python scripts/execute_routine.py \ - --routine-path example_routines/jetblue_one_way_flight_search.json \ - --parameters-path /Users/dimavremenko/Desktop/code/web-hacker/example_routines/jet_blue_input.json + --routine-path routine_discovery_output/routine.json \ + --parameters-path routine_discovery_output/test_parameters.json # Execute routine with parameters from a dictionary python scripts/execute_routine.py \ From b5cb95eedaf6ba09a20d56b615a34d7356f3ed48 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:16 -0500 Subject: [PATCH 14/22] update readme --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 142325c..fad1e52 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Each Routine includes: - **description** — what the Routine does - **parameters** — input values the Routine needs to run (e.g. URLs, credentials, text) - **operations** — the ordered browser actions that perform the automation +- **incognito** — whether to execute in incognito mode (default: `true`) Example: > Navigate to a dashboard, search based on keywords, and return results — all as a reusable Routine. @@ -46,6 +47,12 @@ Example: - Defined as typed inputs (see [`Parameter`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py) class). - Each parameter has required `name` and `description` fields, along with `type`, `required`, and optional `default`/`examples`. - Parameters are referenced inside operations using placeholder tokens like `"{{paramName}}"` or `\"{{paramName}}\"` (see [Placeholder Interpolation](#placeholder-interpolation-) below). +- **Parameter Types**: Supported types include `string`, `integer`, `number`, `boolean`, `date`, `datetime`, `email`, `url`, and `enum`. +- **Parameter Validation**: Parameters support validation constraints such as `min_length`, `max_length`, `min_value`, `max_value`, `pattern` (regex), `enum_values`, and `format`. +- **Reserved Prefixes**: Parameter names cannot start with reserved prefixes: `sessionStorage`, `localStorage`, `cookie`, `meta`, `uuid`, `epoch_milliseconds`. +- **Builtin Parameters**: The following builtin parameters are available without definition: + - `{{uuid}}` — generates a UUID v4 + - `{{epoch_milliseconds}}` — generates current timestamp in milliseconds ### Operations @@ -68,7 +75,10 @@ Each operation specifies a `type` and its parameters: "type": "fetch", "endpoint": { "method": "GET", - "url": "https://api.example.com" + "url": "https://api.example.com", + "headers": {}, + "body": {}, + "credentials": "same-origin" }, "session_storage_key": "userData" } @@ -103,13 +113,17 @@ This defines a deterministic flow: open → wait → authenticate → return a s Placeholders inside operation fields are resolved at runtime: -- Parameter placeholders: `"{{paramName}}"` or `\"{{paramName}}\"` → substituted from routine parameters -- Storage placeholders (read values from the current session): - - `{{sessionStorage:myKey.path.to.value}}` - - `{{localStorage:myKey}}` - - `{{cookie:CookieName}}` +- **Parameter placeholders**: `"{{paramName}}"` or `\"{{paramName}}\"` → substituted from routine parameters +- **Builtin parameters** (no definition required): + - `{{uuid}}` — generates a UUID v4 + - `{{epoch_milliseconds}}` — generates current timestamp in milliseconds +- **Storage placeholders** (read values from the current session): + - `{{sessionStorage:myKey.path.to.value}}` — access nested values in sessionStorage + - `{{localStorage:myKey}}` — access localStorage values + - `{{cookie:CookieName}}` — read cookie values + - `{{meta:name}}` — read meta tag content (e.g., ``) -**Important:** Currently, `sessionStorage`, `localStorage`, and `cookie` placeholder resolution is supported only inside fetch `headers` and `body`. Future versions will support interpolation anywhere in operations. +**Important:** Currently, `sessionStorage`, `localStorage`, `cookie`, and `meta` placeholder resolution is supported only inside fetch `headers` and `body`. Future versions will support interpolation anywhere in operations. Interpolation occurs before an operation executes. For example, a fetch endpoint might be: @@ -235,14 +249,43 @@ Use the CDP browser monitor to block trackers and capture network, storage, and **Run this command to start monitoring:** ```bash +# Basic usage (creates new tab automatically) python scripts/browser_monitor.py \ --host 127.0.0.1 \ --port 9222 \ --output-dir ./cdp_captures \ --url about:blank + +# Use existing tab (provide tab ID) +python scripts/browser_monitor.py \ + --url https://example.com + +# Create incognito tab +python scripts/browser_monitor.py \ + --incognito \ + --url https://example.com + +# Keep existing cookies/storage (don't clear) +python scripts/browser_monitor.py \ + --no-clear-all \ + --url https://example.com ``` -The script will open a new tab (starting at `about:blank`). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically. +**Command Options:** +- `--host`, `--port` — Chrome DevTools address (default: `127.0.0.1:9222`) +- `--url` — Initial URL to navigate to (default: `about:blank`) +- `--output-dir` — Output directory for captures (default: `./cdp_captures`) +- `--incognito` — Create new tab in incognito mode +- `--no-navigate` — Don't navigate, just attach to existing tab +- `--clear-output` / `--keep-output` — Control output directory clearing +- `--capture-resources` — Resource types to capture (default: `XHR Fetch`) +- `--no-clear-cookies` — Don't clear cookies before monitoring (cleared by default) +- `--no-clear-storage` — Don't clear storage before monitoring (cleared by default) +- `--no-clear-all` — Don't clear cookies or storage (convenience flag) + +**Note:** If no tab ID is provided, the script will automatically create a new tab. The tab ID can be obtained from `http://127.0.0.1:9222/json` or Chrome's `chrome://inspect/#devices`. + +The script will open a new tab (starting at the specified URL). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically. **Output structure** (under `--output-dir`, default `./cdp_captures`): @@ -322,28 +365,29 @@ This ensures the parameter value is properly quoted as a JSON string when substi Run the example routine: ``` -# Using a parameters file (see examples in `scripts/execute_routine.py`): +# Using a parameters file: python scripts/execute_routine.py \ - --routine-path example_data/amtrak_one_way_train_search_routine.json \ - --parameters-path example_data/amtrak_one_way_train_search_input.json + --routine-path example_routines/amtrak_one_way_train_search_routine.json \ + --parameters-path example_routines/amtrak_one_way_train_search_input.json - -# Or pass parameters inline (JSON string) — matches the script’s examples: +# Or pass parameters inline (JSON string): python scripts/execute_routine.py \ - --routine-path example_data/amtrak_one_way_train_search_routine.json \ + --routine-path example_routines/amtrak_one_way_train_search_routine.json \ --parameters-dict '{"origin": "boston", "destination": "new york", "departureDate": "2026-03-22"}' ``` -Once you have a routine JSON, run it in a real browser session (same Chrome debug session): +Once you have a routine JSON from discovery, run it in a real browser session: ``` python scripts/execute_routine.py \ - --routine-path routine_discovery_output/routine.json \ - --parameters-path routine_discovery_output/test_parameters.json + --routine-path routine_discovery_output/routine.json \ + --parameters-path routine_discovery_output/test_parameters.json ``` +**Note:** Routines execute in a new incognito tab by default (controlled by the routine's `incognito` field). This ensures clean sessions for each execution. + **Alternative:** Deploy your routine to [console.vectorly.app](https://console.vectorly.app) to expose it as an API endpoint or MCP server for use in production environments. ## Common Issues ⚠️ From 03c29a7ec30a50bc6e818e7215d8710d1e6e8db5 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:18 -0500 Subject: [PATCH 15/22] clarify parameters --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fad1e52..e361b0d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,6 @@ Each Routine includes: - **description** — what the Routine does - **parameters** — input values the Routine needs to run (e.g. URLs, credentials, text) - **operations** — the ordered browser actions that perform the automation -- **incognito** — whether to execute in incognito mode (default: `true`) Example: > Navigate to a dashboard, search based on keywords, and return results — all as a reusable Routine. @@ -45,14 +44,12 @@ Example: ### Parameters - Defined as typed inputs (see [`Parameter`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py) class). -- Each parameter has required `name` and `description` fields, along with `type`, `required`, and optional `default`/`examples`. -- Parameters are referenced inside operations using placeholder tokens like `"{{paramName}}"` or `\"{{paramName}}\"` (see [Placeholder Interpolation](#placeholder-interpolation-) below). +- Each parameter has required `name` and `description` fields. Optional fields include `type` (defaults to `string`), `required` (defaults to `true`), `default`, and `examples`. +- Parameters are referenced inside `operations` using placeholder tokens like `"{{paramName}}"` or `\"{{paramName}}\"` (see [Placeholder Interpolation](#placeholder-interpolation-) below). - **Parameter Types**: Supported types include `string`, `integer`, `number`, `boolean`, `date`, `datetime`, `email`, `url`, and `enum`. - **Parameter Validation**: Parameters support validation constraints such as `min_length`, `max_length`, `min_value`, `max_value`, `pattern` (regex), `enum_values`, and `format`. - **Reserved Prefixes**: Parameter names cannot start with reserved prefixes: `sessionStorage`, `localStorage`, `cookie`, `meta`, `uuid`, `epoch_milliseconds`. -- **Builtin Parameters**: The following builtin parameters are available without definition: - - `{{uuid}}` — generates a UUID v4 - - `{{epoch_milliseconds}}` — generates current timestamp in milliseconds + ### Operations From c51136f30731e8c6ce649636581512d68f3cf4c3 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:21 -0500 Subject: [PATCH 16/22] clarify placeholder interpolation --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e361b0d..13c8643 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,7 @@ Example: ### Operations -Operations define the executable steps of a Routine. -They are represented as a **typed list** (see [`RoutineOperationUnion`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py)) and are executed sequentially by the browser agent. +Operations define the executable steps of a Routine. They are represented as a **typed list** (see [`RoutineOperationUnion`](https://github.com/VectorlyApp/web-hacker/blob/main/src/data_models/production_routine.py)) and are executed sequentially by a browser. Each operation specifies a `type` and its parameters: From 2fd80c0c7452824793e552291209584b3e7c604d Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:23 -0500 Subject: [PATCH 17/22] clarify placeholder interpolation --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 13c8643..4bc2e73 100644 --- a/README.md +++ b/README.md @@ -110,9 +110,6 @@ This defines a deterministic flow: open → wait → authenticate → return a s Placeholders inside operation fields are resolved at runtime: - **Parameter placeholders**: `"{{paramName}}"` or `\"{{paramName}}\"` → substituted from routine parameters -- **Builtin parameters** (no definition required): - - `{{uuid}}` — generates a UUID v4 - - `{{epoch_milliseconds}}` — generates current timestamp in milliseconds - **Storage placeholders** (read values from the current session): - `{{sessionStorage:myKey.path.to.value}}` — access nested values in sessionStorage - `{{localStorage:myKey}}` — access localStorage values From 1c2dcf075e756d6abaa4ca5ecd58cfa7d7042bd0 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:26 -0500 Subject: [PATCH 18/22] simplify monitor section --- README.md | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/README.md b/README.md index 4bc2e73..5083e3f 100644 --- a/README.md +++ b/README.md @@ -242,43 +242,14 @@ Use the CDP browser monitor to block trackers and capture network, storage, and **Run this command to start monitoring:** ```bash -# Basic usage (creates new tab automatically) python scripts/browser_monitor.py \ --host 127.0.0.1 \ --port 9222 \ --output-dir ./cdp_captures \ --url about:blank - -# Use existing tab (provide tab ID) -python scripts/browser_monitor.py \ - --url https://example.com - -# Create incognito tab -python scripts/browser_monitor.py \ - --incognito \ - --url https://example.com - -# Keep existing cookies/storage (don't clear) -python scripts/browser_monitor.py \ - --no-clear-all \ - --url https://example.com ``` -**Command Options:** -- `--host`, `--port` — Chrome DevTools address (default: `127.0.0.1:9222`) -- `--url` — Initial URL to navigate to (default: `about:blank`) -- `--output-dir` — Output directory for captures (default: `./cdp_captures`) -- `--incognito` — Create new tab in incognito mode -- `--no-navigate` — Don't navigate, just attach to existing tab -- `--clear-output` / `--keep-output` — Control output directory clearing -- `--capture-resources` — Resource types to capture (default: `XHR Fetch`) -- `--no-clear-cookies` — Don't clear cookies before monitoring (cleared by default) -- `--no-clear-storage` — Don't clear storage before monitoring (cleared by default) -- `--no-clear-all` — Don't clear cookies or storage (convenience flag) - -**Note:** If no tab ID is provided, the script will automatically create a new tab. The tab ID can be obtained from `http://127.0.0.1:9222/json` or Chrome's `chrome://inspect/#devices`. - -The script will open a new tab (starting at the specified URL). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically. +The script will open a new tab (starting at `about:blank`). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically. **Output structure** (under `--output-dir`, default `./cdp_captures`): From 1eac8fcc719c2a5d0d3c9e2943e9d21207217fe8 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:32:28 -0500 Subject: [PATCH 19/22] fix: example routine --- README.md | 6 ++++-- example_routines/amtrak_one_way_train_search_routine.json | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5083e3f..fd332be 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,8 @@ routine_discovery_output/ ### 3. Execute the Discovered Routines 🏃 +⚠️ **Prerequisite:** Make sure Chrome is still running in debug mode (see [Launch Chrome in Debug Mode](#launch-chrome-in-debug-mode-🐞) above). The routine execution script connects to the same Chrome debug session on `127.0.0.1:9222`. + ⚠️ **Important:** If you have a string-typed parameter used in a JSON body field, it may need to be escaped. When the agent generates routines, string parameters are sometimes placed as `"{{PARAM}}"` when they should be `"\"{{PARAM}}\""` to ensure proper JSON string escaping. **Example:** If you see: @@ -339,10 +341,10 @@ python scripts/execute_routine.py \ python scripts/execute_routine.py \ --routine-path example_routines/amtrak_one_way_train_search_routine.json \ - --parameters-dict '{"origin": "boston", "destination": "new york", "departureDate": "2026-03-22"}' + --parameters-dict '{"origin": "BOS", "destination": "NYP", "departureDate": "2026-03-22"}' ``` -Once you have a routine JSON from discovery, run it in a real browser session: +Run a discovered routine: ``` python scripts/execute_routine.py \ diff --git a/example_routines/amtrak_one_way_train_search_routine.json b/example_routines/amtrak_one_way_train_search_routine.json index 47272a7..a40e612 100644 --- a/example_routines/amtrak_one_way_train_search_routine.json +++ b/example_routines/amtrak_one_way_train_search_routine.json @@ -9,7 +9,7 @@ "type": "fetch", "endpoint": { "description": "Amtrak station/location autocomplete. GET with query parameter searchTerm; returns JSON with autoCompleterResponse.autoCompleteList.", - "url": "https://www.amtrak.com/services/MapDataService/AutoCompleterArcgis/getResponseList?searchTerm={{origin}}", + "url": "https://www.amtrak.com/services/MapDataService/AutoCompleterArcgis/getResponseList?searchTerm=\"{{origin}}\"", "method": "GET", "headers": {"Accept": "application/json, text/plain, */*"}, "body": {}, @@ -21,7 +21,7 @@ "type": "fetch", "endpoint": { "description": "Amtrak station/location autocomplete. GET with query parameter searchTerm; returns JSON with autoCompleterResponse.autoCompleteList.", - "url": "https://www.amtrak.com/services/MapDataService/AutoCompleterArcgis/getResponseList?searchTerm={{destination}}", + "url": "https://www.amtrak.com/services/MapDataService/AutoCompleterArcgis/getResponseList?searchTerm=\"{{destination}}\"", "method": "GET", "headers": {"Accept": "application/json, text/plain, */*"}, "body": {}, @@ -55,7 +55,7 @@ { "origin": { "code": "{{sessionStorage:amtrak_autocomplete_stations_origin.autoCompleterResponse.autoCompleteList.0.stationCode}}", - "schedule": {"departureDateTime": "{{departureDate}}T00:00:00"} + "schedule": {"departureDateTime": "\"{{departureDate}}\"T00:00:00"} }, "destination": { "code": "{{sessionStorage:amtrak_autocomplete_stations_destination.autoCompleterResponse.autoCompleteList.0.stationCode}}" From 6bfa36c3fc27c9f52f0c86ed13ab64427171d1c0 Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:20:36 -0500 Subject: [PATCH 20/22] include codeowners --- CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..6f7d681 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,6 @@ +# CODEOWNERS file +# This file defines ownership of the codebase. +# When a PR modifies files, GitHub will automatically request reviews from the listed owners. + +# Owners for the entire repository +* @alex-w-99 @dimavrem22 @rayruizhiliao \ No newline at end of file From 6be335a59cc104893ae086cefc0655300e7fe69e Mon Sep 17 00:00:00 2001 From: Ray Liao <17989965+rayruizhiliao@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:20:45 -0500 Subject: [PATCH 21/22] fix: routine discovery agent issues --- src/routine_discovery/agent.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routine_discovery/agent.py b/src/routine_discovery/agent.py index e934d56..6f9640a 100644 --- a/src/routine_discovery/agent.py +++ b/src/routine_discovery/agent.py @@ -418,13 +418,13 @@ def resolve_variables(self, extracted_variables: ExtractedVariableResponse) -> l storage_sources = self.context_manager.scan_storage_for_value( value=value ) - storage_sources.extend(storage_sources) + storage_objects.extend(storage_sources) - if len(storage_sources) > 0: - print(f"Found {len(storage_sources)} storage sources that contain the value") + if len(storage_objects) > 0: + print(f"Found {len(storage_objects)} storage sources that contain the value") # get the transaction ids that contain the value and are before the latest timestamp - transaction_ids = {} + transaction_ids = [] for value in variable.values_to_scan_for: transaction_ids.extend(self.context_manager.scan_transaction_responses( value=value, max_timestamp=max_timestamp @@ -605,7 +605,7 @@ def productionize_routine(self, routine: Routine) -> Routine: f"and the surrounding quotes are removed, so \\\"{{{{item_id}}}}\\\" with value 42 becomes just 42 (valid JSON number, not string). " f"Example: \\\"{{{{total_price}}}}\\\" with value 29.99 → becomes 29.99 (quotes removed, valid JSON number). " f"Example: \\\"{{{{optional_data}}}}\\\" with null → becomes null (quotes removed, valid JSON null). " - """Placeholders will be resolved using this: param_pattern = r'(?:"|\\")\{\{([^}"]*)\}\}(?:"|\\")'""" + """Placeholders will be resolved using this: param_pattern = r'(?:"|\\\\")\\{\\{([^}"]*)\\}\\}(?:"|\\\\")'""" f"The resulting JSON MUST be valid and parseable after all placeholder replacements are done." ) self._add_to_message_history("user", message) From 015feb9c6451d747706ca0ca060708e259a1ef6f Mon Sep 17 00:00:00 2001 From: Dima Vremenko <90374336+dimavrem22@users.noreply.github.com> Date: Mon, 3 Nov 2025 22:27:27 -0500 Subject: [PATCH 22/22] Update README to include incognito option Added incognito flag to browser_monitor.py script usage. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd332be..bec2d64 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,8 @@ python scripts/browser_monitor.py \ --host 127.0.0.1 \ --port 9222 \ --output-dir ./cdp_captures \ - --url about:blank + --url about:blank \ + --incognito ``` The script will open a new tab (starting at `about:blank`). Navigate to your target website, then manually perform the actions you want to automate (e.g., search, login, export report). Keep Chrome focused during this process. Press `Ctrl+C` when done; the script will consolidate transactions and produce a HAR automatically.