AI & Product Engineering / Apartspace case study
From Conversation to Booking: Inside Solomiia on Semitexa
A guest describes a stay. The product must find actual properties, calculate an actual price, and put a request in front of someone who can accept it. Solomiia, Apartspace’s AI concierge, connects those steps through a Semitexa application. Follow the code to see where conversation becomes business work.
A short message can contain an entire workflow
Imagine a guest writing: “We need a quiet apartment in Lviv for two people, November 10–17.” This is an illustrative request, rather than a recorded guest conversation. Inside it are a city, a party size, a date interval, and a preference. To help, the product has to connect those words to its inventory and the rules of a stay.
In Apartspace, Solomiia has defined actions for searching listings, quoting a stay, reviewing booking details, and creating a booking request. Each action enters application code. Listings and request cards are assembled from the tool results. A guest can move from describing a need to a concrete property and a request the owner can act on.
The useful unit here is the complete journey. A polished answer helps only if the dates, price, property, and next step stay connected.
The execution path
- Guest intentCity, dates, people, preferences
- Defined actionSearch, quote, review, request
- Application rulesInventory, rate services, validation
- Visible resultProperty cards, a quote, a request link
Give the model a vocabulary the application understands
ActionProtocol defines the concierge’s action vocabulary, including search_listings, quote_stay, review_booking, and create_booking_request. It maps provider-native tool calls and a JSON fallback into the same normalized action structure. Unknown action names fall back to a reply.
A search action carries fields such as city, guest count, dates, preferences, and budget. A booking action carries a listing identifier, dates, and contact details. Those boundaries give SolomiiaToolExecutor specific operations to dispatch. The model’s suggestion then meets the actual data stores and services.
The orchestrator separates deciding from narrating. The decision stage receives tools and may execute a bounded sequence of actions. The narration stage receives their results with an empty tool list. That second stage can explain what happened, while the application builds the displayed listing cards from collected listing data.
Conversation history and a structured notebook carry context between turns. Signed-in guests have an account notebook; anonymous guests use conversation context. This helps successive messages build on a search. It still leaves interpretation dependent on the model, so actual action parameters need their own validation.
The price comes from the rate service
A guest eventually asks, “What will this stay cost?” Solomiia’s quote action looks up the active listing and calls the application’s rate service for its account, property, and dates. The result contains the rent, deposit, and currency. The narration stage can explain these amounts using the returned data.
Creating a request also obtains a fresh quote. The stored rent total and currency come from that quote. A model-supplied price has no parameter in this creation path. This is a concrete architectural guarantee: the amount written to the booking request is supplied by application pricing.
The booking guard checks for a listing identifier, parseable dates, a checkout after check-in, a stay that does not start in the past, a name, and a basic phone format. The executor uses the property’s market date for the past-date check and limits the guest count to the listing’s configured maximum. These are specific checks, with specific limits: the phone check does not verify ownership of the number.
If the rate service cannot quote the stay, the executor returns an error result. The application needs a usable quote before it creates the request. The conversational layer can then explain why the attempted next step failed.
Review, request, and confirmation have different effects
Rental products have several moments that can sound like “booking” in ordinary conversation. Apartspace gives them separate operations:
| Stage | Application effect | Who acts |
|---|---|---|
| Review | Build a summary of the property, dates, contact details, and quoted rent. | The concierge presents the proposed request. |
| Request | Persist a priced booking request and return its signed status link. | The guest asks to proceed through the concierge. |
| Confirmation | Attempt the booking transition and calendar reservation. | An authorized owner or manager decides. |
The review action prepares its summary using the active listing and a fresh quote. The request action repeats validation and quoting before persistence. Its result includes a server-generated status URL with a signed token, so the interface can show the guest an actionable request card.
A consent boundary deserves an exact description. The current decider prompt instructs Solomiia to show a summary before creating a request. A review fingerprint records the listing, dates, name, and phone. If creation does not match the recorded review, the executor logs solomiia.booking_unconfirmed, but still proceeds after its other checks. That fingerprint currently measures the review flow; it does not enforce a mandatory confirmation gate.
This distinction matters when designing a conversational product. A required approval step needs a server-side refusal when approval is missing. Prompt instructions and mismatch logging have useful roles, but the present implementation does not make that approval an invariant. The owner’s subsequent confirmation remains a separate operation.
The owner’s decision enters the booking workflow
A booking request must reach someone authorized to handle the property. The inspected Telegram callback path checks a signed callback bound to the user, resolves the booking, verifies the user’s current owner or manager role, and requires the booking to remain in the requested state.
Confirmation then calls BookingStore::confirmRequest(). This is the application’s booking operation, with its calendar and transition rules. The callback handles slot overlap and invalid transitions as failure outcomes. A conversational promise cannot bypass those checks.
The confirmation result can also report competing requests declined by the operation. This is why the guest-facing request and the owner’s acceptance need separate meanings: until the confirmation path succeeds, the conversation has produced a request awaiting a decision.
Keep the workflow inspectable after the conversation
SolomiiaOrchestrator allows up to three acting rounds per turn. It records the models used, tool rounds, call and token counts, latency, and whether the turn produced a request. The conversation journal and notebook carry the state used by later turns.
These records give developers concrete questions to investigate: which action was selected, what the application returned, whether a request was created, and whether its details matched a shown review. They help distinguish an interpretation problem from a rejected application operation.
The boundaries also have limits. Restricting actions and keeping stored prices in application services does not prove that every narrated sentence will be accurate. An owner authorization check does not prove the guest supplied a genuine phone number. Each guarantee should be attached to the operation that actually enforces it.
Semitexa gives the conversation a place to become work
Solomiia’s protocol, executor, notebooks, and booking rules are Apartspace application code. The project uses Semitexa’s LLM integration and application structure alongside its data, identity, access, rendering, and event capabilities. The framework provides paths into the rest of the product; Apartspace defines the rental behavior.
This case shows a practical way to build AI into a business application. Start with a useful customer journey. Give the model defined actions. Implement the operations using authoritative services. Return results the interface can display. Then make approval, authorization, and state changes explicit wherever the business requires them.
Our 32-hour Apartspace case study examines delivery speed and the wider product. Here, the evidence is the connection itself: a guest’s words reach real inventory, pricing, persistence, and an owner’s decision through inspectable application code.
What was checked for this article
This article follows the inspected Apartspace source as of September 30, 2026. The main implementation references are ActionProtocol, SolomiiaOrchestrator, SolomiiaToolExecutor, BookingParamsGuard, BookingReviewFingerprint, and TelegramBookingCallbackListener.
The focused test selection for action parsing, booking parameter validation, review fingerprints, notebooks, request-link signing, and callback signing passed: 95 tests, 275 assertions. These unit checks support the covered behavior. The review did not create a live booking, measure conversational accuracy, or run a production journey from guest message to owner acceptance.
Source locations and verification scope
The concierge implementation lives under src/modules/Assistant/src/. Owner callbacks and booking persistence live under src/modules/Booking/src/. The inspected repository HEAD was 1645740; claims refer to the local source snapshot, which can include work beyond that commit.
The PHPUnit selection covered ActionProtocolTest, BookingParamsGuardTest, BookingReviewFingerprintTest, NotebookTest, RequestLinkSignerTest, and BookingCallbackSignerTest. Signing tests establish the covered token behavior; authorization claims above come from inspecting the callback’s role and state checks.
Build around the next useful action. If a conversation should end in a quote, request, or operational decision, give each step an application contract and enforce its business rules in code.