imprint-mcp 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +6 -4
  2. package/examples/discoverandgo/README.md +1 -1
  3. package/examples/discoverandgo/book_discoverandgo_museum_pass/workflow.json +7 -0
  4. package/examples/google-flights/README.md +41 -14
  5. package/examples/google-flights/_shared/google_batchexecute_parser.ts +165 -0
  6. package/examples/google-flights/_shared/google_flights_transport.ts +70 -0
  7. package/examples/google-flights/_shared/google_flights_types.ts +56 -0
  8. package/examples/google-flights/get_flight_booking_options/backends.json +43 -0
  9. package/examples/google-flights/get_flight_booking_options/index.ts +129 -0
  10. package/examples/google-flights/get_flight_booking_options/parser.ts +209 -0
  11. package/examples/google-flights/get_flight_booking_options/playbook.yaml +46 -0
  12. package/examples/google-flights/get_flight_booking_options/request-transform.ts +210 -0
  13. package/examples/google-flights/get_flight_booking_options/workflow.json +85 -0
  14. package/examples/google-flights/get_flight_calendar_prices/backends.json +27 -0
  15. package/examples/google-flights/get_flight_calendar_prices/index.ts +44 -29
  16. package/examples/google-flights/get_flight_calendar_prices/parser.ts +76 -69
  17. package/examples/google-flights/get_flight_calendar_prices/playbook.yaml +67 -40
  18. package/examples/google-flights/get_flight_calendar_prices/workflow.json +29 -17
  19. package/examples/google-flights/get_flight_location_details/backends.json +27 -0
  20. package/examples/google-flights/{lookup_airport → get_flight_location_details}/index.ts +30 -20
  21. package/examples/google-flights/get_flight_location_details/parser.ts +103 -0
  22. package/examples/google-flights/get_flight_location_details/playbook.yaml +59 -0
  23. package/examples/google-flights/{lookup_airport → get_flight_location_details}/workflow.json +19 -12
  24. package/examples/google-flights/lookup_flight_locations/backends.json +27 -0
  25. package/examples/google-flights/lookup_flight_locations/index.ts +111 -0
  26. package/examples/google-flights/lookup_flight_locations/package.json +9 -0
  27. package/examples/google-flights/lookup_flight_locations/parser.ts +135 -0
  28. package/examples/google-flights/lookup_flight_locations/playbook.yaml +47 -0
  29. package/examples/google-flights/lookup_flight_locations/request-transform.ts +53 -0
  30. package/examples/google-flights/lookup_flight_locations/workflow.json +64 -0
  31. package/examples/google-flights/search_flights/backends.json +42 -0
  32. package/examples/google-flights/search_flights/index.ts +105 -69
  33. package/examples/google-flights/search_flights/parser.ts +186 -183
  34. package/examples/google-flights/search_flights/playbook.yaml +295 -88
  35. package/examples/google-flights/search_flights/request-transform.ts +247 -92
  36. package/examples/google-flights/search_flights/workflow.json +66 -40
  37. package/examples/google-flights/validate_flight_itinerary/backends.json +27 -0
  38. package/examples/google-flights/validate_flight_itinerary/index.ts +103 -0
  39. package/examples/google-flights/validate_flight_itinerary/package.json +9 -0
  40. package/examples/google-flights/validate_flight_itinerary/parser.ts +101 -0
  41. package/examples/google-flights/validate_flight_itinerary/playbook.yaml +84 -0
  42. package/examples/google-flights/validate_flight_itinerary/request-transform.ts +92 -0
  43. package/examples/google-flights/validate_flight_itinerary/workflow.json +59 -0
  44. package/examples/google-hotels/README.md +40 -15
  45. package/examples/google-hotels/get_hotel_details/backends.json +16 -0
  46. package/examples/google-hotels/get_hotel_details/index.ts +122 -0
  47. package/examples/google-hotels/get_hotel_details/parser.ts +275 -0
  48. package/examples/google-hotels/get_hotel_details/playbook.yaml +40 -0
  49. package/examples/google-hotels/get_hotel_details/request-transform.ts +67 -0
  50. package/examples/google-hotels/get_hotel_details/workflow.json +67 -0
  51. package/examples/google-hotels/get_hotel_photos/backends.json +16 -0
  52. package/examples/google-hotels/get_hotel_photos/index.ts +90 -0
  53. package/examples/google-hotels/get_hotel_photos/parser.ts +75 -0
  54. package/examples/google-hotels/get_hotel_photos/playbook.yaml +23 -0
  55. package/examples/google-hotels/get_hotel_photos/request-transform.ts +27 -0
  56. package/examples/google-hotels/get_hotel_photos/workflow.json +44 -0
  57. package/examples/google-hotels/get_hotel_reviews/backends.json +16 -0
  58. package/examples/google-hotels/get_hotel_reviews/index.ts +14 -17
  59. package/examples/google-hotels/get_hotel_reviews/parser.ts +177 -105
  60. package/examples/google-hotels/get_hotel_reviews/playbook.yaml +9 -54
  61. package/examples/google-hotels/get_hotel_reviews/workflow.json +10 -13
  62. package/examples/google-hotels/get_travel_area_boundaries/backends.json +16 -0
  63. package/examples/google-hotels/get_travel_area_boundaries/index.ts +104 -0
  64. package/examples/google-hotels/get_travel_area_boundaries/package.json +9 -0
  65. package/examples/google-hotels/get_travel_area_boundaries/parser.ts +127 -0
  66. package/examples/google-hotels/get_travel_area_boundaries/playbook.yaml +38 -0
  67. package/examples/google-hotels/get_travel_area_boundaries/request-transform.ts +52 -0
  68. package/examples/google-hotels/get_travel_area_boundaries/workflow.json +54 -0
  69. package/examples/google-hotels/list_hotel_booking_options/backends.json +16 -0
  70. package/examples/google-hotels/list_hotel_booking_options/index.ts +123 -0
  71. package/examples/google-hotels/list_hotel_booking_options/package.json +9 -0
  72. package/examples/google-hotels/list_hotel_booking_options/parser.ts +308 -0
  73. package/examples/google-hotels/list_hotel_booking_options/playbook.yaml +95 -0
  74. package/examples/google-hotels/list_hotel_booking_options/request-transform.ts +77 -0
  75. package/examples/google-hotels/list_hotel_booking_options/workflow.json +67 -0
  76. package/examples/google-hotels/search_hotel_web_links/backends.json +16 -0
  77. package/examples/google-hotels/search_hotel_web_links/index.ts +90 -0
  78. package/examples/google-hotels/search_hotel_web_links/package.json +9 -0
  79. package/examples/google-hotels/search_hotel_web_links/parser.ts +96 -0
  80. package/examples/google-hotels/search_hotel_web_links/playbook.yaml +53 -0
  81. package/examples/google-hotels/search_hotel_web_links/request-transform.ts +17 -0
  82. package/examples/google-hotels/search_hotel_web_links/workflow.json +43 -0
  83. package/examples/google-hotels/search_hotels/backends.json +16 -0
  84. package/examples/google-hotels/search_hotels/index.ts +32 -102
  85. package/examples/google-hotels/search_hotels/parser.ts +237 -216
  86. package/examples/google-hotels/search_hotels/playbook.yaml +177 -42
  87. package/examples/google-hotels/search_hotels/request-transform.ts +101 -170
  88. package/examples/google-hotels/search_hotels/workflow.json +24 -73
  89. package/examples/google-hotels/suggest_hotel_destinations/backends.json +16 -0
  90. package/examples/google-hotels/{autocomplete_hotel_location → suggest_hotel_destinations}/index.ts +30 -19
  91. package/examples/google-hotels/suggest_hotel_destinations/package.json +9 -0
  92. package/examples/google-hotels/suggest_hotel_destinations/parser.ts +138 -0
  93. package/examples/google-hotels/suggest_hotel_destinations/playbook.yaml +47 -0
  94. package/examples/google-hotels/suggest_hotel_destinations/request-transform.ts +33 -0
  95. package/examples/google-hotels/suggest_hotel_destinations/workflow.json +44 -0
  96. package/examples/southwest/README.md +31 -70
  97. package/examples/southwest/get_account_details/backends.json +22 -0
  98. package/examples/southwest/get_account_details/credentials.manifest.json +17 -0
  99. package/examples/southwest/get_account_details/index.ts +138 -0
  100. package/examples/{google-hotels/_shared → southwest/get_account_details}/package.json +2 -2
  101. package/examples/southwest/get_account_details/parser.ts +136 -0
  102. package/examples/southwest/get_account_details/playbook.yaml +19 -0
  103. package/examples/southwest/get_account_details/workflow.json +93 -0
  104. package/examples/southwest/get_flight_status/backends.json +21 -0
  105. package/examples/southwest/get_flight_status/index.ts +130 -0
  106. package/examples/southwest/get_flight_status/package.json +9 -0
  107. package/examples/southwest/get_flight_status/parser.ts +138 -0
  108. package/examples/southwest/get_flight_status/playbook.yaml +58 -0
  109. package/examples/southwest/get_flight_status/workflow.json +77 -0
  110. package/examples/southwest/get_low_fare_calendar/backends.json +21 -0
  111. package/examples/southwest/get_low_fare_calendar/index.ts +134 -0
  112. package/examples/southwest/get_low_fare_calendar/package.json +9 -0
  113. package/examples/southwest/get_low_fare_calendar/parser.ts +107 -0
  114. package/examples/southwest/get_low_fare_calendar/playbook.yaml +41 -0
  115. package/examples/southwest/get_low_fare_calendar/workflow.json +81 -0
  116. package/examples/southwest/list_upcoming_trips/backends.json +22 -0
  117. package/examples/southwest/list_upcoming_trips/credentials.manifest.json +17 -0
  118. package/examples/southwest/list_upcoming_trips/index.ts +123 -0
  119. package/examples/southwest/list_upcoming_trips/package.json +9 -0
  120. package/examples/southwest/list_upcoming_trips/parser.ts +160 -0
  121. package/examples/southwest/list_upcoming_trips/playbook.yaml +24 -0
  122. package/examples/southwest/list_upcoming_trips/workflow.json +78 -0
  123. package/examples/southwest/search_flights/backends.json +21 -0
  124. package/examples/southwest/search_flights/index.ts +150 -0
  125. package/examples/southwest/search_flights/package.json +9 -0
  126. package/examples/southwest/search_flights/parser.ts +214 -0
  127. package/examples/southwest/search_flights/playbook.yaml +52 -0
  128. package/examples/southwest/search_flights/workflow.json +88 -0
  129. package/package.json +1 -1
  130. package/prompts/audit-agent.md +2 -1
  131. package/prompts/build-planning.md +22 -1
  132. package/prompts/compile-agent.md +66 -53
  133. package/prompts/prereq-builder.md +3 -1
  134. package/prompts/tool-planning.md +2 -0
  135. package/src/cli.ts +8 -3
  136. package/src/imprint/audit.ts +337 -44
  137. package/src/imprint/backend-cache.ts +114 -0
  138. package/src/imprint/backend-ladder.ts +74 -24
  139. package/src/imprint/bot-defense.ts +12 -0
  140. package/src/imprint/build-plan.ts +346 -53
  141. package/src/imprint/cdp-browser-fetch.ts +96 -43
  142. package/src/imprint/cdp-jar-cache.ts +6 -5
  143. package/src/imprint/chromium.ts +34 -0
  144. package/src/imprint/codex-cli-compile.ts +13 -2
  145. package/src/imprint/compile-agent.ts +3 -1
  146. package/src/imprint/compile-tools.ts +715 -138
  147. package/src/imprint/compile.ts +41 -9
  148. package/src/imprint/concurrency.ts +26 -3
  149. package/src/imprint/cron.ts +0 -3
  150. package/src/imprint/endpoint-key.ts +23 -0
  151. package/src/imprint/llm-url.ts +69 -0
  152. package/src/imprint/llm.ts +366 -47
  153. package/src/imprint/login.ts +83 -75
  154. package/src/imprint/mcp-compile-server.ts +4 -1
  155. package/src/imprint/mcp-server.ts +51 -16
  156. package/src/imprint/param-grounding.ts +61 -52
  157. package/src/imprint/probe-backends.ts +21 -115
  158. package/src/imprint/redact.ts +17 -15
  159. package/src/imprint/request-capture.ts +94 -0
  160. package/src/imprint/runtime.ts +1 -78
  161. package/src/imprint/session-diff.ts +14 -1
  162. package/src/imprint/stealth-fetch.ts +30 -20
  163. package/src/imprint/stealth-token-cache.ts +2 -2
  164. package/src/imprint/teach-plan.ts +2 -0
  165. package/src/imprint/teach-state.ts +14 -9
  166. package/src/imprint/teach.ts +41 -7
  167. package/src/imprint/telemetry.ts +3 -0
  168. package/src/imprint/tool-candidates.ts +8 -7
  169. package/src/imprint/tool-plan.ts +29 -3
  170. package/src/imprint/tracing.ts +18 -2
  171. package/examples/google-flights/_shared/batchexecute.ts +0 -63
  172. package/examples/google-flights/_shared/flights_request.ts +0 -97
  173. package/examples/google-flights/get_flight_booking_details/index.ts +0 -159
  174. package/examples/google-flights/get_flight_booking_details/parser.ts +0 -182
  175. package/examples/google-flights/get_flight_booking_details/playbook.yaml +0 -138
  176. package/examples/google-flights/get_flight_booking_details/request-transform.ts +0 -86
  177. package/examples/google-flights/get_flight_booking_details/workflow.json +0 -98
  178. package/examples/google-flights/get_flight_calendar_prices/request-transform.ts +0 -31
  179. package/examples/google-flights/lookup_airport/parser.ts +0 -66
  180. package/examples/google-flights/lookup_airport/playbook.yaml +0 -47
  181. package/examples/google-flights/lookup_airport/request-transform.ts +0 -20
  182. package/examples/google-hotels/_shared/batchexecute.ts +0 -73
  183. package/examples/google-hotels/_shared/freq.ts +0 -158
  184. package/examples/google-hotels/autocomplete_hotel_location/parser.ts +0 -71
  185. package/examples/google-hotels/autocomplete_hotel_location/playbook.yaml +0 -36
  186. package/examples/google-hotels/autocomplete_hotel_location/request-transform.ts +0 -37
  187. package/examples/google-hotels/autocomplete_hotel_location/workflow.json +0 -36
  188. package/examples/google-hotels/get_hotel_booking_options/index.ts +0 -143
  189. package/examples/google-hotels/get_hotel_booking_options/parser.ts +0 -271
  190. package/examples/google-hotels/get_hotel_booking_options/playbook.yaml +0 -154
  191. package/examples/google-hotels/get_hotel_booking_options/request-transform.ts +0 -154
  192. package/examples/google-hotels/get_hotel_booking_options/workflow.json +0 -84
  193. package/examples/google-hotels/get_hotel_reviews/request-transform.ts +0 -42
  194. package/examples/southwest/search_southwest_flights/backends.json +0 -23
  195. package/examples/southwest/search_southwest_flights/cron.json +0 -19
  196. package/examples/southwest/search_southwest_flights/index.ts +0 -127
  197. package/examples/southwest/search_southwest_flights/playbook.yaml +0 -46
  198. package/examples/southwest/search_southwest_flights/workflow.json +0 -71
  199. /package/examples/google-flights/{get_flight_booking_details → get_flight_booking_options}/package.json +0 -0
  200. /package/examples/google-flights/{lookup_airport → get_flight_location_details}/package.json +0 -0
  201. /package/examples/google-hotels/{autocomplete_hotel_location → get_hotel_details}/package.json +0 -0
  202. /package/examples/google-hotels/{get_hotel_booking_options → get_hotel_photos}/package.json +0 -0
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Tool: get_flight_calendar_prices
5
5
  * Site: google-flights
6
- * Intent: Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.
6
+ * Intent: Get Google Flights calendar fare prices for candidate departure and return dates.
7
7
  *
8
8
  * To regenerate: imprint emit ~/.imprint/google-flights/get_flight_calendar_prices/workflow.json --force
9
9
  */
@@ -19,35 +19,47 @@ import type { ToolResult, Workflow } from 'imprint/types';
19
19
  const WORKFLOW: Workflow = {
20
20
  "toolName": "get_flight_calendar_prices",
21
21
  "intent": {
22
- "description": "Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.",
23
- "userSaid": "searched for a round trip flight; SJC to SAN"
22
+ "description": "Get Google Flights calendar fare prices for candidate departure and return dates.",
23
+ "userSaid": "searched for a round trip flight"
24
24
  },
25
25
  "parameters": [
26
26
  {
27
27
  "name": "origin",
28
28
  "type": "string",
29
- "description": "Origin airport IATA code, e.g. SJC",
29
+ "description": "Origin airport code, city code, or place identifier.",
30
+ "default": "SJC",
30
31
  "verified": false,
31
32
  "verifyNote": "annotated"
32
33
  },
33
34
  {
34
35
  "name": "destination",
35
36
  "type": "string",
36
- "description": "Destination airport IATA code, e.g. SAN",
37
+ "description": "Destination airport code, city code, or place identifier.",
38
+ "default": "SAN",
37
39
  "verified": false,
38
40
  "verifyNote": "annotated"
39
41
  },
40
42
  {
41
43
  "name": "start_date",
42
44
  "type": "string",
43
- "description": "Start of departure-date window, YYYY-MM-DD",
45
+ "description": "Start of date range in YYYY-MM-DD format.",
46
+ "default": "2026-05-24",
44
47
  "verified": false,
45
48
  "verifyNote": "annotated"
46
49
  },
47
50
  {
48
51
  "name": "end_date",
49
52
  "type": "string",
50
- "description": "End of departure-date window, YYYY-MM-DD",
53
+ "description": "End of date range in YYYY-MM-DD format.",
54
+ "default": "2026-06-30",
55
+ "verified": false,
56
+ "verifyNote": "annotated"
57
+ },
58
+ {
59
+ "name": "trip_length",
60
+ "type": "string",
61
+ "description": "Desired round-trip stay length encoded as a JSON array, such as [7,7] for exactly seven nights.",
62
+ "default": "[7,7]",
51
63
  "verified": false,
52
64
  "verifyNote": "annotated"
53
65
  }
@@ -55,55 +67,57 @@ const WORKFLOW: Workflow = {
55
67
  "requests": [
56
68
  {
57
69
  "method": "POST",
58
- "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=1508023&rt=c",
70
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=${generated.epoch_ms}&rt=c",
59
71
  "headers": {
60
72
  "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
61
73
  "X-Same-Domain": "1",
74
+ "X-Goog-BatchExecute-Bgr": "[\";Ax24HXnQAAZ9xeyCXcVfQlm-O5f3IMQmAEABEArZ1HslyK_BQ4JUKKyty1YaNnvwE0sZIvxZhduE37esgzJCv9uMqDEE1XWJ18RMdQIqq0x78ZaVDYUSpNlkHwAAADRPAAAAA3UBB2MAQlf4Dur8CYS7BGnPB7Iacw3MphUBUI2W-YWb5e8PhXYs-8TUiv6viHhKnooYK5Zh4Bn8BBnjIZRYQcbsJOpFS3ZhooQDMQVPZtietR5D0nXyywzsouTKdgfr-GRsjHAUlFxRsdTnP5169CGPpxrG1D0RMatGaVAf0M36ShU86Y4maDJeysl1scNfvkas-OzyjVF5YrvzbvXAAyZPIS5j1dr9tEXukNKcD1Jw4z5ZzB2pO1gn7nOlo1fQ4OcQnBjhJesq2h4o-LV5hCp2M3dWaLs83Z2d1yRVJHtrDHsCAFKiwAXAOYLsUZuudogTEucsNMX99na4rWfoLD5ccN159OWWW2TenwRa0lKq5aiFxXsJxD25al6H_w_vMZXswB33fovMNoz0o1kFp9OD1qu-X14ts4n0cFlLUeMztzLeGJREyMt2j58Rwcoyf7Exwu5OIgVPPYfoJGCShTdAtystQqvLld2xkUuHWaj2UxiAqSH63PGKJ4xCvcDSMnV6qbXeqStlJEg3rbpNdAsNEGzw5XSyJ54TYH7q_loLQqRdZttrvL_FnlDDFQLcOyNiwXo-2HnNtbUNvcNUrtRVlbnOkaM6L9LKd5lqd2T2ehRm-Tn9YgaKvRBT38Ja2MhR8Yu2kN2WspglRfBMvrzlyRZeu0hp0QeSQowIV0IJqHOMZbAkJ5nUFo23sPg-vCiV2MsSvTeiRSLIe_R0qOH5u_UzxD1mmg7A7-Af-YRG5lnFxl9GuDLAXdyqMMXnsTwVwicln6bF4dfGAoXS0_8YNOPdX1OfZEfypJaMOodYI-R2hH0G_Gc-HlLb_m2KU605V4aPi31gQPvQIp7SQdLiBajE-pQXsF5Am9CfQEkkHeIQasRtHWsEmWz8Dyr3pLu8gOx2IHzevgNdLrqLLcGLqysWxXRK-f7ftjMYvOADGAwTZ7vC_fg8HcLwiCcliIrt4oIWPBfiKh86mJ6_rFh07j50xwBKCyVft8iX8qqrRpj8mUvdD5TxJkC2OlGdX3_hrtU0y46WIX1HjUtiqILu9dShE3VErqkEOS5uHVQrr4fKXholojoNsLQj5DNREkQ7-ajRqcwN4tF3KCHBIapjB0tygaUqxwcy-bRp0qHCJn6q2iSYMGEOmQkj0jHGavGmlAIDC_ZbbhOSgN_OixbX-VN4yqjwbgnh7GE\",null,null,214,8,null,null,0,\"5\"]",
62
75
  "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]",
63
- "Referer": "https://www.google.com/travel/flights",
64
- "Accept-Language": "en-US,en;q=0.9"
76
+ "Referer": "https://www.google.com/travel/flights?tfs=CBwQARoSagcIARIDU0pDcgcIARIDU0FOGhJqBwgBEgNTQU5yBwgBEgNTSkNAAUgBcAGCAQsI____________AZgBAQ&tfu=KgIIAw"
65
77
  },
66
- "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C%5B7%2C7%5D%5D%22%5D&",
78
+ "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C${param.trip_length}%5D%22%5D",
67
79
  "effect": "safe"
68
80
  }
69
81
  ],
70
82
  "site": "google-flights",
71
83
  "bootstrap": {
72
- "url": "https://www.google.com/travel/flights?hl=en-US&curr=USD",
84
+ "url": "https://www.google.com/travel/flights?tfs=CBwQARoSagcIARIDU0pDcgcIARIDU0FOGhJqBwgBEgNTQU5yBwgBEgNTSkNAAUgBcAGCAQsI____________AZgBAQ&tfu=KgIIAw",
73
85
  "waitUntil": "domcontentloaded",
74
86
  "captures": [
75
87
  {
76
88
  "name": "f_sid",
77
- "required": false,
89
+ "required": true,
78
90
  "capability": "browser_bootstrap",
79
91
  "source": "html_regex",
80
- "pattern": "\"FdrFJe\":\"([^\"]+)\"",
92
+ "pattern": "\\\"FdrFJe\\\":\\\"([^\\\"]+)\\\"",
81
93
  "group": 1
82
94
  },
83
95
  {
84
96
  "name": "bl",
85
- "required": false,
97
+ "required": true,
86
98
  "capability": "browser_bootstrap",
87
99
  "source": "html_regex",
88
- "pattern": "\"cfb2h\":\"([^\"]+)\"",
100
+ "pattern": "\\\"cfb2h\\\":\\\"([^\\\"]+)\\\"",
89
101
  "group": 1
90
102
  }
91
103
  ]
92
104
  },
93
105
  "parserModule": "./parser.ts",
94
- "requestTransformModule": "./request-transform.ts",
106
+ "requestTransformModule": "../_shared/google_flights_transport.ts",
95
107
  "liveVerified": true
96
108
  };
97
109
 
98
110
  export interface GetFlightCalendarPricesInput {
99
- /** Origin airport IATA code, e.g. SJC */
100
- origin: string;
101
- /** Destination airport IATA code, e.g. SAN */
102
- destination: string;
103
- /** Start of departure-date window, YYYY-MM-DD */
104
- start_date: string;
105
- /** End of departure-date window, YYYY-MM-DD */
106
- end_date: string;
111
+ /** Origin airport code, city code, or place identifier. */
112
+ origin?: string;
113
+ /** Destination airport code, city code, or place identifier. */
114
+ destination?: string;
115
+ /** Start of date range in YYYY-MM-DD format. */
116
+ start_date?: string;
117
+ /** End of date range in YYYY-MM-DD format. */
118
+ end_date?: string;
119
+ /** Desired round-trip stay length encoded as a JSON array, such as [7,7] for exactly seven nights. */
120
+ trip_length?: string;
107
121
  }
108
122
 
109
123
  export async function getFlightCalendarPrices(
@@ -112,10 +126,11 @@ export async function getFlightCalendarPrices(
112
126
  ): Promise<ToolResult> {
113
127
  const __dirname = dirname(fileURLToPath(import.meta.url));
114
128
  const params: Record<string, string | number | boolean> = {
115
- origin: input.origin,
116
- destination: input.destination,
117
- start_date: input.start_date,
118
- end_date: input.end_date,
129
+ origin: input.origin ?? "SJC",
130
+ destination: input.destination ?? "SAN",
131
+ start_date: input.start_date ?? "2026-05-24",
132
+ end_date: input.end_date ?? "2026-06-30",
133
+ trip_length: input.trip_length ?? "[7,7]",
119
134
 
120
135
  };
121
136
  return executeWorkflow({
@@ -1,86 +1,93 @@
1
- // Parse a Google Flights GetCalendarPicker batchexecute response into a
2
- // date->price calendar for the route. Decoding of the )]}' envelope is delegated
3
- // to the shared batchexecute helper (imported per the build plan).
4
- import { decodeBatchExecute } from '../_shared/batchexecute.ts';
1
+ import { extractWrbRecords, parseNestedPayload } from '../_shared/google_batchexecute_parser.ts';
2
+ import type { CalendarPrice } from '../_shared/google_flights_types.ts';
5
3
 
6
- type CalendarEntry = {
7
- departureDate: string;
8
- returnDate: string | null;
9
- lowestPriceUSD: number;
4
+ type CalendarOutput = {
5
+ items: CalendarPrice[];
6
+ count: number;
7
+ currency: string;
10
8
  };
11
9
 
12
- const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
10
+ function asArray(value: unknown): unknown[] | null {
11
+ return Array.isArray(value) ? value : null;
12
+ }
13
13
 
14
- // The GetCalendarPicker wrb.fr payload is shaped:
15
- // [ <metadata>, [ [depDate, retDate, [[null, price], token], 1], ... ] ]
16
- // The metadata entry is skipped naturally because we only keep array items whose
17
- // [0] is an ISO date string. We scan every nested array so we are robust to the
18
- // list living at payload[1] (the recorded shape) or being flattened.
19
- function collectEntries(payload: unknown): CalendarEntry[] {
20
- const entries = new Map<string, CalendarEntry>();
21
- if (!Array.isArray(payload)) return [];
14
+ function parsePayload(rawResponse: unknown): unknown[] | null {
15
+ if (Array.isArray(rawResponse)) return rawResponse;
22
16
 
23
- const consider = (item: unknown) => {
24
- if (!Array.isArray(item)) return;
25
- const dep = item[0];
26
- if (typeof dep !== 'string' || !ISO_DATE.test(dep)) return;
27
- const ret = typeof item[1] === 'string' && ISO_DATE.test(item[1]) ? (item[1] as string) : null;
28
- // price lives at item[2][0][1]
29
- const priceContainer = item[2];
30
- let price: unknown = null;
31
- if (Array.isArray(priceContainer) && Array.isArray(priceContainer[0])) {
32
- price = (priceContainer[0] as unknown[])[1];
33
- }
34
- if (typeof price !== 'number') return; // no fare found for that date -> omit
35
- const existing = entries.get(dep);
36
- if (!existing || price < existing.lowestPriceUSD) {
37
- entries.set(dep, { departureDate: dep, returnDate: ret, lowestPriceUSD: price });
38
- }
39
- };
17
+ if (typeof rawResponse !== 'string') return null;
18
+
19
+ const records = extractWrbRecords(rawResponse);
20
+ const record = records.find((entry) => Array.isArray(parseNestedPayload(entry.payload)));
21
+ if (!record) return null;
40
22
 
41
- for (const top of payload) {
42
- if (Array.isArray(top)) {
43
- // top may itself be the list of date entries, or a single entry.
44
- consider(top);
45
- for (const inner of top) consider(inner);
46
- }
47
- }
48
- return [...entries.values()];
23
+ const payload = parseNestedPayload(record.payload);
24
+ return asArray(payload);
25
+ }
26
+
27
+ function dateDiffDays(start: string, end: string): number | undefined {
28
+ const startMs = Date.parse(`${start}T00:00:00Z`);
29
+ const endMs = Date.parse(`${end}T00:00:00Z`);
30
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return undefined;
31
+ return Math.round((endMs - startMs) / 86_400_000);
32
+ }
33
+
34
+ function readCurrency(token: string | undefined): string {
35
+ if (!token) return 'USD';
36
+ return token.includes('VVNE') || token.includes('USD') ? 'USD' : 'USD';
49
37
  }
50
38
 
51
39
  export function extract(
52
40
  rawResponse: unknown,
53
- context?: { params?: Record<string, string | number | boolean>; responses?: unknown[] },
54
- ): unknown {
55
- const raw = typeof rawResponse === 'string' ? rawResponse : JSON.stringify(rawResponse ?? '');
56
- const frames = decodeBatchExecute(raw);
41
+ context?: { params: Record<string, string | number | boolean>; responses: unknown[] },
42
+ ): CalendarOutput {
43
+ const payload = parsePayload(rawResponse);
44
+ const rows = asArray(payload?.[1]) ?? [];
57
45
 
58
- let payload: unknown = null;
59
- for (const f of frames) {
60
- const candidate = collectEntries(f.payload);
61
- if (candidate.length > 0) {
62
- payload = f.payload;
63
- break;
64
- }
65
- }
66
- // If no frame produced entries, still attempt the first frame's payload so an
67
- // empty (zero-result) response yields an empty calendar rather than throwing.
68
- if (payload == null && frames.length > 0) payload = frames[0]?.payload ?? null;
46
+ const parsedItems = rows
47
+ .map((row): CalendarPrice | null => {
48
+ const entry = asArray(row);
49
+ if (!entry) return null;
69
50
 
70
- const entries = collectEntries(payload).sort((a, b) =>
71
- a.departureDate < b.departureDate ? -1 : a.departureDate > b.departureDate ? 1 : 0,
72
- );
51
+ const departureDate = typeof entry[0] === 'string' ? entry[0] : '';
52
+ const returnDate = typeof entry[1] === 'string' ? entry[1] : undefined;
53
+ const priceBlock = asArray(entry[2]);
54
+ const priceTuple = asArray(priceBlock?.[0]);
55
+ const rawPrice = priceTuple?.[1];
56
+ const price = typeof rawPrice === 'number' ? rawPrice : undefined;
57
+ const selectionToken = typeof priceBlock?.[1] === 'string' ? priceBlock[1] : undefined;
58
+
59
+ if (!departureDate && !returnDate && price === undefined && !selectionToken) return null;
60
+ if (!departureDate) return null;
73
61
 
74
- const prices: Record<string, number> = {};
75
- for (const e of entries) prices[e.departureDate] = e.lowestPriceUSD;
62
+ const nights = returnDate ? dateDiffDays(departureDate, returnDate) : undefined;
63
+ const requestedTripLength = context?.params?.trip_length;
64
+ const tripLength = nights !== undefined ? `${nights} nights` : requestedTripLength ? String(requestedTripLength) : undefined;
65
+
66
+ return {
67
+ departureDate,
68
+ returnDate,
69
+ price,
70
+ currency: readCurrency(selectionToken),
71
+ tripLength,
72
+ selectionToken,
73
+ };
74
+ })
75
+ .filter((item): item is CalendarPrice => item !== null);
76
+ const items = Array.from(
77
+ parsedItems
78
+ .reduce((bestByDeparture, item) => {
79
+ const current = bestByDeparture.get(item.departureDate);
80
+ if (!current || (item.price ?? Number.POSITIVE_INFINITY) < (current.price ?? Number.POSITIVE_INFINITY)) {
81
+ bestByDeparture.set(item.departureDate, item);
82
+ }
83
+ return bestByDeparture;
84
+ }, new Map<string, CalendarPrice>())
85
+ .values(),
86
+ );
76
87
 
77
- const params = context?.params ?? {};
78
88
  return {
79
- origin: params.origin != null ? String(params.origin).toUpperCase() : null,
80
- destination: params.destination != null ? String(params.destination).toUpperCase() : null,
81
- currency: 'USD',
82
- count: entries.length,
83
- prices,
84
- calendar: entries,
89
+ items,
90
+ count: items.length,
91
+ currency: items[0]?.currency ?? 'USD',
85
92
  };
86
93
  }
@@ -1,56 +1,89 @@
1
1
  toolName: get_flight_calendar_prices
2
- summary: Open the Google Flights date picker for a route to capture the calendar grid of lowest prices by departure/return date.
2
+ summary: Get Google Flights calendar fare prices for a route after opening the date picker.
3
3
  parameters:
4
4
  - name: origin
5
5
  type: string
6
- description: Origin airport code, e.g. SJC
6
+ description: Origin airport code, city code, or place identifier.
7
7
  - name: destination
8
8
  type: string
9
- description: Destination airport code, e.g. SAN
9
+ description: Destination airport code, city code, or place identifier.
10
+ - name: trip_type
11
+ type: string
12
+ description: Trip type such as round_trip or one_way.
13
+ default: round_trip
10
14
  - name: start_date
11
15
  type: string
12
- description: Start of date window YYYY-MM-DD (used to filter the returned calendar range; the picker returns a fixed window starting near today)
16
+ description: Start of date range in YYYY-MM-DD format.
13
17
  - name: end_date
14
18
  type: string
15
- description: End of date window YYYY-MM-DD (used to filter the returned calendar range)
19
+ description: End of date range in YYYY-MM-DD format.
20
+ - name: trip_length
21
+ type: string
22
+ description: Optional desired trip length or min/max nights for round-trip calendars.
23
+ default: "7 nights"
16
24
  steps:
17
25
  - action: navigate
18
- url: https://www.google.com/travel/flights
26
+ url: "https://www.google.com/travel/flights"
19
27
  wait_for: networkidle
20
28
  - action: click
21
29
  locators:
22
30
  - by: role
23
- value: combobox
24
- name: "Where from?"
31
+ value: button
32
+ name: Round trip
33
+ - by: text
34
+ value: Round trip
35
+ - by: css
36
+ value: "div.TQYpgc.gInvKb div.VfPpkd-aPP78e"
37
+ wait_for:
38
+ sleep_ms: 300
39
+ - action: click
40
+ locators:
41
+ - by: role
42
+ value: option
43
+ name: Round trip
44
+ - by: text
45
+ value: Round trip
46
+ - by: css
47
+ value: "ul[aria-label='Select your ticket type.'] li"
48
+ wait_for: visible
49
+ - action: click
50
+ locators:
25
51
  - by: aria_label
26
- value: "Where from?"
52
+ value: Where from?
53
+ - by: text
54
+ value_pattern: Where from
55
+ - by: css
56
+ value: "input[aria-label^='Where from']"
27
57
  wait_for:
28
58
  sleep_ms: 300
29
59
  - action: type
30
60
  locators:
31
61
  - by: aria_label
32
- value: "Where from?"
62
+ value: Where else?
33
63
  - by: aria_label
34
- value: "Where else?"
35
- value: ${origin}
64
+ value_pattern: Where from
65
+ - by: css
66
+ value: "input.II2One"
67
+ value: "${origin}"
36
68
  wait_for:
37
69
  sleep_ms: 500
38
70
  - action: click
39
71
  locators:
40
72
  - by: aria_label
41
- value_pattern: ${origin}
42
- - by: role
43
- value: option
73
+ value_pattern: "${origin}"
74
+ - by: text
75
+ value_pattern: "${origin}"
44
76
  - by: css
45
- value: "ul.DFGgtd > li.n4HaVc"
77
+ value: "ul.DFGgtd li"
46
78
  wait_for: visible
47
79
  - action: click
48
80
  locators:
49
- - by: role
50
- value: combobox
51
- name: "Where to?"
52
81
  - by: aria_label
53
82
  value: "Where to? "
83
+ - by: text
84
+ value_pattern: Where to
85
+ - by: css
86
+ value: "input[aria-label^='Where to']"
54
87
  wait_for:
55
88
  sleep_ms: 300
56
89
  - action: type
@@ -58,40 +91,34 @@ steps:
58
91
  - by: aria_label
59
92
  value: "Where to? "
60
93
  - by: aria_label
61
- value: "Where else?"
62
- value: ${destination}
94
+ value: Where else?
95
+ - by: css
96
+ value: "input.II2One"
97
+ value: "${destination}"
63
98
  wait_for:
64
99
  sleep_ms: 500
65
100
  - action: click
66
101
  locators:
67
102
  - by: aria_label
68
- value_pattern: ${destination}
69
- - by: role
70
- value: option
103
+ value_pattern: "${destination}"
104
+ - by: text
105
+ value_pattern: "${destination}"
71
106
  - by: css
72
- value: "ul.DFGgtd > li.n4HaVc"
107
+ value: "ul.DFGgtd li"
73
108
  wait_for: visible
74
109
  - action: click
75
110
  locators:
76
111
  - by: aria_label
77
112
  value: Departure
113
+ - by: text
114
+ value_pattern: Departure
78
115
  - by: css
79
- value: "div.GYgkab.YICvqf > div.NA5Egc.ESCxub > input.TP4Lpb.eoY5cb"
116
+ value: "input[aria-label='Departure']"
80
117
  wait_for:
81
- xhr: /GetCalendarPicker
118
+ xhr: GetCalendarPicker
82
119
  result:
83
120
  source: xhr
84
- url_pattern: /GetCalendarPicker
85
- extract: "[1][]"
121
+ url_pattern: GetCalendarPicker
122
+ extract: "wrb.fr"
86
123
  return_as: calendar_prices
87
- notes: >-
88
- The GetCalendarPicker response is a Google batchexecute payload: strip the )]}' prefix, split on
89
- numeric length-prefix lines, and JSON.parse the "wrb.fr" envelope's third element (a JSON-encoded
90
- string). Inside that decoded array, index [1] is the list of date entries; each entry is
91
- [departureDate (YYYY-MM-DD), returnDate (YYYY-MM-DD), [[null, lowestPriceUSD], opaqueFlightToken], 1].
92
- Build a departureDate->lowestPriceUSD map and filter to [start_date, end_date]. The extract path
93
- "[1][]" is relative to the decoded wrb.fr payload, not the raw HTTP body. start_date/end_date are
94
- client-side filters: the picker returns a fixed forward window (~from today) and is opened simply by
95
- clicking the Departure field — no date is typed to drive the request. The request is authorized by a
96
- per-page f.sid plus X-Goog-BatchExecute-Bgr header that must be captured fresh from the page bootstrap
97
- (navigate step), not parameterized.
124
+ notes: Google Flights returns the calendar response inside a batchexecute/WIZ envelope; downstream parsing must strip the JSON prefix, parse the wrb.fr payload string, and map each fare row as departure date, return date, price amount, encoded selection token, and availability flag. The captured calendar for SJC to SAN returned rows shaped like date, return date, price tuple, and flag, e.g. 2026-06-08 to 2026-06-15 at 242 USD.
@@ -1,58 +1,70 @@
1
1
  {
2
2
  "toolName": "get_flight_calendar_prices",
3
+ "site": "google-flights",
3
4
  "intent": {
4
- "description": "Get a calendar grid of lowest round-trip prices by departure date for a route over a date window.",
5
- "userSaid": "searched for a round trip flight; SJC to SAN"
5
+ "description": "Get Google Flights calendar fare prices for candidate departure and return dates.",
6
+ "userSaid": "searched for a round trip flight"
6
7
  },
7
- "site": "google-flights",
8
8
  "parameters": [
9
9
  {
10
10
  "name": "origin",
11
11
  "type": "string",
12
- "description": "Origin airport IATA code, e.g. SJC",
12
+ "description": "Origin airport code, city code, or place identifier.",
13
+ "default": "SJC",
13
14
  "verified": false,
14
15
  "verifyNote": "annotated"
15
16
  },
16
17
  {
17
18
  "name": "destination",
18
19
  "type": "string",
19
- "description": "Destination airport IATA code, e.g. SAN",
20
+ "description": "Destination airport code, city code, or place identifier.",
21
+ "default": "SAN",
20
22
  "verified": false,
21
23
  "verifyNote": "annotated"
22
24
  },
23
25
  {
24
26
  "name": "start_date",
25
27
  "type": "string",
26
- "description": "Start of departure-date window, YYYY-MM-DD",
28
+ "description": "Start of date range in YYYY-MM-DD format.",
29
+ "default": "2026-05-24",
27
30
  "verified": false,
28
31
  "verifyNote": "annotated"
29
32
  },
30
33
  {
31
34
  "name": "end_date",
32
35
  "type": "string",
33
- "description": "End of departure-date window, YYYY-MM-DD",
36
+ "description": "End of date range in YYYY-MM-DD format.",
37
+ "default": "2026-06-30",
38
+ "verified": false,
39
+ "verifyNote": "annotated"
40
+ },
41
+ {
42
+ "name": "trip_length",
43
+ "type": "string",
44
+ "description": "Desired round-trip stay length encoded as a JSON array, such as [7,7] for exactly seven nights.",
45
+ "default": "[7,7]",
34
46
  "verified": false,
35
47
  "verifyNote": "annotated"
36
48
  }
37
49
  ],
38
50
  "bootstrap": {
39
- "url": "https://www.google.com/travel/flights?hl=en-US&curr=USD",
51
+ "url": "https://www.google.com/travel/flights?tfs=CBwQARoSagcIARIDU0pDcgcIARIDU0FOGhJqBwgBEgNTQU5yBwgBEgNTSkNAAUgBcAGCAQsI____________AZgBAQ&tfu=KgIIAw",
40
52
  "waitUntil": "domcontentloaded",
41
53
  "captures": [
42
54
  {
43
55
  "source": "html_regex",
44
56
  "name": "f_sid",
45
- "pattern": "\"FdrFJe\":\"([^\"]+)\"",
57
+ "pattern": "\\\"FdrFJe\\\":\\\"([^\\\"]+)\\\"",
46
58
  "group": 1,
47
- "required": false,
59
+ "required": true,
48
60
  "capability": "browser_bootstrap"
49
61
  },
50
62
  {
51
63
  "source": "html_regex",
52
64
  "name": "bl",
53
- "pattern": "\"cfb2h\":\"([^\"]+)\"",
65
+ "pattern": "\\\"cfb2h\\\":\\\"([^\\\"]+)\\\"",
54
66
  "group": 1,
55
- "required": false,
67
+ "required": true,
56
68
  "capability": "browser_bootstrap"
57
69
  }
58
70
  ]
@@ -60,19 +72,19 @@
60
72
  "requests": [
61
73
  {
62
74
  "method": "POST",
63
- "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=1508023&rt=c",
75
+ "url": "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarPicker?f.sid=${state.f_sid}&bl=${state.bl}&hl=en-US&soc-app=162&soc-platform=1&soc-device=1&_reqid=${generated.epoch_ms}&rt=c",
64
76
  "headers": {
65
77
  "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
66
78
  "X-Same-Domain": "1",
79
+ "X-Goog-BatchExecute-Bgr": "[\";Ax24HXnQAAZ9xeyCXcVfQlm-O5f3IMQmAEABEArZ1HslyK_BQ4JUKKyty1YaNnvwE0sZIvxZhduE37esgzJCv9uMqDEE1XWJ18RMdQIqq0x78ZaVDYUSpNlkHwAAADRPAAAAA3UBB2MAQlf4Dur8CYS7BGnPB7Iacw3MphUBUI2W-YWb5e8PhXYs-8TUiv6viHhKnooYK5Zh4Bn8BBnjIZRYQcbsJOpFS3ZhooQDMQVPZtietR5D0nXyywzsouTKdgfr-GRsjHAUlFxRsdTnP5169CGPpxrG1D0RMatGaVAf0M36ShU86Y4maDJeysl1scNfvkas-OzyjVF5YrvzbvXAAyZPIS5j1dr9tEXukNKcD1Jw4z5ZzB2pO1gn7nOlo1fQ4OcQnBjhJesq2h4o-LV5hCp2M3dWaLs83Z2d1yRVJHtrDHsCAFKiwAXAOYLsUZuudogTEucsNMX99na4rWfoLD5ccN159OWWW2TenwRa0lKq5aiFxXsJxD25al6H_w_vMZXswB33fovMNoz0o1kFp9OD1qu-X14ts4n0cFlLUeMztzLeGJREyMt2j58Rwcoyf7Exwu5OIgVPPYfoJGCShTdAtystQqvLld2xkUuHWaj2UxiAqSH63PGKJ4xCvcDSMnV6qbXeqStlJEg3rbpNdAsNEGzw5XSyJ54TYH7q_loLQqRdZttrvL_FnlDDFQLcOyNiwXo-2HnNtbUNvcNUrtRVlbnOkaM6L9LKd5lqd2T2ehRm-Tn9YgaKvRBT38Ja2MhR8Yu2kN2WspglRfBMvrzlyRZeu0hp0QeSQowIV0IJqHOMZbAkJ5nUFo23sPg-vCiV2MsSvTeiRSLIe_R0qOH5u_UzxD1mmg7A7-Af-YRG5lnFxl9GuDLAXdyqMMXnsTwVwicln6bF4dfGAoXS0_8YNOPdX1OfZEfypJaMOodYI-R2hH0G_Gc-HlLb_m2KU605V4aPi31gQPvQIp7SQdLiBajE-pQXsF5Am9CfQEkkHeIQasRtHWsEmWz8Dyr3pLu8gOx2IHzevgNdLrqLLcGLqysWxXRK-f7ftjMYvOADGAwTZ7vC_fg8HcLwiCcliIrt4oIWPBfiKh86mJ6_rFh07j50xwBKCyVft8iX8qqrRpj8mUvdD5TxJkC2OlGdX3_hrtU0y46WIX1HjUtiqILu9dShE3VErqkEOS5uHVQrr4fKXholojoNsLQj5DNREkQ7-ajRqcwN4tF3KCHBIapjB0tygaUqxwcy-bRp0qHCJn6q2iSYMGEOmQkj0jHGavGmlAIDC_ZbbhOSgN_OixbX-VN4yqjwbgnh7GE\",null,null,214,8,null,null,0,\"5\"]",
67
80
  "x-goog-ext-259736195-jspb": "[\"en-US\",\"US\",\"USD\",2,null,[420],null,null,7,[]]",
68
- "Referer": "https://www.google.com/travel/flights",
69
- "Accept-Language": "en-US,en;q=0.9"
81
+ "Referer": "https://www.google.com/travel/flights?tfs=CBwQARoSagcIARIDU0pDcgcIARIDU0FOGhJqBwgBEgNTQU5yBwgBEgNTSkNAAUgBcAGCAQsI____________AZgBAQ&tfu=KgIIAw"
70
82
  },
71
- "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C%5B7%2C7%5D%5D%22%5D&",
83
+ "body": "f.req=%5Bnull%2C%22%5Bnull%2C%5Bnull%2Cnull%2C1%2Cnull%2C%5B%5D%2C1%2C%5B1%2C0%2C0%2C0%5D%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2Cnull%2C%5B%5B%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%2C%5B%5B%5B%5B%5C%22${param.destination}%5C%22%2C0%5D%5D%5D%2C%5B%5B%5B%5C%22${param.origin}%5C%22%2C0%5D%5D%5D%2Cnull%2C0%5D%5D%2Cnull%2Cnull%2Cnull%2C1%5D%2C%5B%5C%22${param.start_date}%5C%22%2C%5C%22${param.end_date}%5C%22%5D%2Cnull%2C${param.trip_length}%5D%22%5D",
72
84
  "effect": "safe"
73
85
  }
74
86
  ],
75
- "requestTransformModule": "./request-transform.ts",
76
87
  "parserModule": "./parser.ts",
88
+ "requestTransformModule": "../_shared/google_flights_transport.ts",
77
89
  "liveVerified": true
78
90
  }
@@ -0,0 +1,27 @@
1
+ {
2
+ "probedAt": "2026-07-01T01:13:31.308Z",
3
+ "imprintVersion": "0.5.0",
4
+ "schemaVersion": 2,
5
+ "workflowHash": "e4390d3c3661046a30bf54d1fead60e7739c62235436080867e0c82f2bea8a23",
6
+ "capabilityHash": "5fc16811cd65aff7afee349ddca05c806a65c9c2c96948192ea1bafba9284c38",
7
+ "preferredOrder": [
8
+ "cdp-replay"
9
+ ],
10
+ "results": {
11
+ "fetch": {
12
+ "outcome": "failed",
13
+ "durationMs": 17,
14
+ "error": "STATE_MISSING",
15
+ "detail": "STATE_MISSING: Workflow placeholder ${state.bl} but state \"bl\" has not been captured yet"
16
+ },
17
+ "fetch-bootstrap": {
18
+ "outcome": "forbidden",
19
+ "durationMs": 30230,
20
+ "detail": "FORBIDDEN: fetch-bootstrap: cdp-minted jar did not validate; cdp-replay (in-page) required."
21
+ },
22
+ "cdp-replay": {
23
+ "outcome": "ok",
24
+ "durationMs": 597
25
+ }
26
+ }
27
+ }