Add library support for booking offers#102
Open
kvasdopil wants to merge 2 commits intopunitarani:mainfrom
Open
Add library support for booking offers#102kvasdopil wants to merge 2 commits intopunitarani:mainfrom
kvasdopil wants to merge 2 commits intopunitarani:mainfrom
Conversation
d0b0743 to
0e2d347
Compare
Contributor
Author
Why no changes to mcp/cli?Running
That brings up 2 problems: how to reliably pass all search params from 1 to 2, including One option would be storing those in short-lived local cache and exposing some sort of @punitarani any opinions on that? |
92c9f7a to
3ba6907
Compare
3ba6907 to
729748b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
This PR adds Python library support for fetching booking offers for a specific itinerary returned by Google Flights search.
At a high level:
SearchFlights.search(...)now preserves the Google booking token on eachFlightResultSearchFlights.get_booking_offers(...)performs a singleGetBookingResultslookup for an exact itineraryfli/search/booking_offers.pymoduleBookingOffermodelWhy
Today the library can find itineraries, but it does not expose the next step a consumer usually needs: where that itinerary can actually be booked and at what merchant price.
Google Flights already returns enough information to do this in two steps:
This PR exposes that flow in the Python library without changing the CLI or MCP surfaces.
API Shape
Example usage:
For round-trip results, pass the returned itinerary tuple directly:
Each
BookingOfferincludes:Scope
This PR is intentionally limited to the Python library:
Notes
get_booking_offers(...)is a single booking-results lookup once you already have the itinerary fromsearch()booking_urlis Google Flights' clickthrough URL, not the final resolved merchant landing URLbooking_tokenremains onFlightResultfor now so offer lookup stays explicit and statelessTesting
/Users/lexa/projects/fli/.venv/bin/python -m pytest -q tests/search/test_booking_results.py/Users/lexa/projects/fli/.venv/bin/python -m ruff check fli/models/__init__.py fli/models/google_flights/__init__.py fli/models/google_flights/base.py fli/search/flights.py fli/search/booking_offers.py tests/search/test_booking_results.pyGreptile Summary
This PR extends the
fliPython library with a two-step booking-offer flow:SearchFlights.search()now preserves abooking_tokenon eachFlightResult, and a newget_booking_offers()method uses that token to call Google Flights'GetBookingResultsendpoint and return a list of typedBookingOfferobjects. A dedicatedfli/search/booking_offers.pymodule isolates request-building and response-parsing logic. The PR is intentionally scoped to the Python library surface — no CLI or MCP changes are included.Key observations:
build_booking_filter_blockandbuild_booking_f_reqare called outside thetry/exceptblock inget_booking_offers, so anyValidationError(e.g. past-dated flight),IndexError, or serialization failure escapes without the"Booking offer lookup failed"wrapper that the method promises.build_booking_filter_blockaccessesflight.legs[0]andflight.legs[-1]unconditionally; aFlightResultwith an emptylegslist would raise a bareIndexError.__import__in tests: Uses__import__("urllib.parse").parse.unquote(...)instead of a top-levelimport urllib.parse.get_booking_offershas only a one-liner; the other public methods onSearchFlightscarry full Google-styleArgs/Returns/Raisesdocumentation.Confidence Score: 4/5
Safe to merge after moving filter-building calls inside the try/except block in get_booking_offers.
One P1 issue remains: exceptions from build_booking_filter_block and build_booking_f_req propagate unwrapped, breaking the error-handling contract that the rest of SearchFlights establishes. The fix is a small mechanical change. All other findings are P2 style/quality suggestions that do not block correctness.
fli/search/flights.py — the try/except scope in get_booking_offers needs to cover the filter-building phase.
Important Files Changed
get_booking_offersand_parse_booking_tokentoSearchFlights; filter-building calls sit outside thetry/except, so validation or serialization failures surface as unwrapped exceptions rather than the documented "Booking offer lookup failed" error.build_booking_filter_blockaccessesflight.legs[0]/legs[-1]without guarding against an emptylegslist.booking_tokentoFlightResultand a newBookingOfferPydantic model; changes are non-breaking and backward-compatible.__import__dynamic import instead of a top-levelurllib.parseimport.BookingOfferfrom the top-level models package; straightforward and complete.Sequence Diagram
sequenceDiagram participant Caller participant SearchFlights participant booking_offers as booking_offers.py participant Google as Google Flights API Caller->>SearchFlights: search(filters) SearchFlights->>Google: POST GetShoppingResults (f.req) Google-->>SearchFlights: raw response (wrb.fr payloads) SearchFlights->>SearchFlights: _parse_flights_data() + _parse_booking_token() SearchFlights-->>Caller: list[FlightResult] (with booking_token) Caller->>SearchFlights: get_booking_offers(itinerary) SearchFlights->>booking_offers: build_booking_filter_block(flights, ...) booking_offers-->>SearchFlights: filter_block SearchFlights->>booking_offers: build_booking_f_req(booking_token, filter_block) booking_offers-->>SearchFlights: encoded f.req SearchFlights->>Google: POST GetBookingResults (f.req) Google-->>SearchFlights: raw response (wrb.fr payloads) SearchFlights->>booking_offers: parse_booking_results(response.text) booking_offers-->>SearchFlights: list[BookingOffer] SearchFlights-->>Caller: list[BookingOffer]Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Add library support for booking offers" | Re-trigger Greptile
(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!
Context used: