<usecase>
Stateful grocery shopping tool for Shipt. Sets a delivery address, selects a retailer, searches for products, and manages the cart across a multi-turn session.
Use for starting or continuing a shopping session, adding items, editing the cart, or switching retailers.
Do NOT use for browsing or comparing products across retailers — use the browse tool for that.
</usecase>
<state>
The server stores delivery address, selected retailer, shopping cart, and query history per session.
- anonymous_id: omit on the very first call. If the server returns one, re-send it on every subsequent call. Never fabricate a new one mid-session.
- If anonymous_id is null on the response from a successful call, the user is authenticated and their identity is derived from tokens provided outside the tool body.
</state>
<flow>
First call - Initial Onboarding:
Send item_queries (when available) and address if the user explicitly provided one in their prompt.
Address resolution — always call Shop, do NOT pre-prompt for an address on initial call:
For initial calls, always call Shop first and let the server decide if additional address information is needed.
1. Address included in this call → use it.
2. Address found in session storage → use it (covers returning guests and authenticated users with a prior session).
3. Authenticated user with no session address → server fetches the user's default saved address.
4. No address available anywhere → server will return a validation error. Only then prompt the user for an address or zip code.
Returns available_retailers for the widget to display.
The widget handles retailer selection and automatically re-submits any pending item_queries after the user picks one.
Do NOT attempt to select a retailer yourself after the first call — wait for the widget.
Do NOT wait for retailer selection before sending item_queries — ALWAYS send them on the first call if available from user.
Ongoing shopping:
Send anonymous_id + item_queries and/or item_edits. Address and retailer are stored — do not re-send them.
</flow>
<operations>
CHANGE ADDRESS:
- Clarify if they want to try and move over existing items before changing the address.
- Send a new address value with item_queries if they wanted to move over existing items. This triggers a new retailer lookup. The widget will display the new retailers for selection and re-submit any pending item_queries.
SWITCH RETAILER:
- Clarify if they want to try and move over existing items before switching.
- Terms like "transfer" or "move my cart" indicate they want to keep items, call to shop should include item_queries.
- "switch" or "change store" without transfer language should prompt clarification before proceeding. If they confirm they want to switch without keeping items, call with just the new store_id and no item_queries.
- If user wants to change selected retailer and you already have the new requested store_id from prior session data, you can call shop directly with the new store_id (with/without item_queries depending on intent).
- If you are not absolutely certain of the new store_id, call shop without store_id and indicate to the user that they can select a new retailer within the rendered widget.
ADD ITEMS: send item_queries. Batch ALL items into one call — never split items across multiple calls.
EDIT CART: send item_edits using product_id values from a prior response's cart_items.
REPLACE ITEM:
Replace item by query (preferred): send item_edits to set the old item's quantity to 0, and item_queries with the replacement search term — both in the same call.
- Example: replace whole milk (product_id: 101) with oat milk →
item_edits: [{"product_id": 101, "quantity": 0}], item_queries: [{"query": "oat milk", "quantity": 1}]
Replace item by product ID: if you have the replacement product_id from the user or a prior browse tool call, send item_edits with the original product_id and replacement_product_id. Preserves the original search query context.
- Example: replace whole milk (product_id: 101) with a specific oat milk (product_id: 202) →
item_edits: [{"product_id": 101, "quantity": 1, "replacement_product_id": 202}]
REPLACE CART CONTENTS: send item_queries + replace_cart=true. Empties cart first, then adds matched items only.
- If no queries match, the cart is left UNCHANGED (no clear occurs).
CLEAR CART: send replace_cart=true with no item_queries. Empties the cart immediately.
GET CART: shop call with no input arguments will retreive the current cart.
</operations>
<parameter_rules>
address
- Omit unless the user explicitly provided an address in their prompt.
- The server resolves the address automatically from session storage or the user's saved profile — do not ask for it upfront.
- Only prompt the user for an address if the server returns an error indicating one is required.
- Resending the same address triggers an unnecessary retailer lookup — avoid this.
- NEVER fabricate an address.
- Send either zip_code alone, or street1 + city + state + zip_code (all four required together when any are present).
store_id
- Only send store_id when the user wants to switch their current retailer and you already have the store_id from prior session data.
- Never fabricate or guess a store_id.
- Sending a different store_id switches the retailer. The cart is persistent — items are not cleared when switching.
- All shopping calls should omit store_id — the server remembers it. Only relevant when user is requesting to switch retailers.
item_queries
- ALWAYS batch ALL items into a single call — never make separate calls per item.
GOOD: item_queries: [{"query": "milk", "quantity": 2}, {"query": "eggs", "quantity": 1}]
BAD: Two separate calls — one for "milk", one for "eggs"
- NEVER include measurement units, sizes, or volume in the query string. Use quantity for amounts.
GOOD: {"query": "milk", "quantity": 2}
BAD: {"query": "gallon of milk", "quantity": 2} — "gallon" is ignored by search
GOOD: {"query": "eggs", "quantity": 1}
BAD: {"query": "dozen eggs", "quantity": 1} — "dozen" is ignored
- Each query auto-selects the best matching product and adds it to the cart.
item_edits
- Use product_id values from cart_items in a prior response. Never fabricate product IDs.
- Set quantity to 0 to remove an item from the cart.
- Set replacement_product_id (from a prior call to browse tool) to swap for a different product while preserving the original search query context.
- Can be combined with item_queries in a single call.
replace_cart
- With item_queries and at least one match: empties cart, then adds matched items only.
- With item_queries but no matches: cart is left UNCHANGED — no clear occurs.
- With no item_queries: clears the entire cart immediately.
- Ignored when no retailer is selected.
</parameter_rules>
<response_rules>
CRITICAL: Always follow the guidelines array in the response — it contains authoritative runtime instructions for display and behavior.
DO NOT list or describe available retailers — the widget displays them.
DO NOT list or describe search results — the widget displays them.
DO NOT re-call this tool automatically after an operation. Always wait for explicit user input.
</response_rules>
Shop