From 6df526bf2729b9b299cb42607e26565758bb7b08 Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Wed, 9 Sep 2026 23:24:08 +0700 Subject: [PATCH] Sasquatch: local fast-path for finder questions (kills ~30s AI wait) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of the ~35s "spots in bangkok" response: every live-data question first waited on an AI round-trip just to produce a tool call, and the keyless backup model (Pollinations) can take tens of seconds. The relay query and local formatting were already fast — the AI was the bottleneck. Fix: before touching the AI, try parseLocalIntent(). For clear finder questions (spots/events/coaches/crews/shops/tours/gear + community stats + weather with a parseable location) we now go STRAIGHT to the relays (capped at 4.5s) and render locally — zero AI calls. Expected ~35s → ~2–4s on the most common queries. Deliberately still routed through the AI: - trip planning (needs the rich itinerary card) - personal "my …" Pro queries (get_my_* tools) - anything without a confidently-parseable intent/location If the fast-path relay query errors, it falls through to the existing AI loop as a backup, so nothing regresses. Co-authored-by: shakespeare.diy --- src/components/SasquatchGuide.tsx | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/components/SasquatchGuide.tsx b/src/components/SasquatchGuide.tsx index 028d527..bce8626 100644 --- a/src/components/SasquatchGuide.tsx +++ b/src/components/SasquatchGuide.tsx @@ -864,6 +864,68 @@ export function SasquatchGuide({ message, onDismiss }: SasquatchGuideProps) { return; } + // 1d. LOCAL FAST-PATH — the big speed win. + // For clear finder questions ("spots in bangkok", "events in lisbon", + // "coaches near berlin", "community stats", "weather in X") we can parse + // the intent + location ourselves and go STRAIGHT to the relays — skipping + // the AI entirely. Previously every live query waited on an AI round-trip + // just to produce a tool call, which is what made these take ~30s+. + // + // We deliberately DON'T fast-path: + // • trip planning (needs the rich itinerary card + AI nuance) + // • personal "my …" queries (Pro tools handled by the AI path) + // Those fall through to the AI loop below. + const isPersonalQuery = /\bmy (stash|gear|crew|crews|spots?|listings?|inventory)\b|what am i selling|what do i own/i.test(question); + const fastIntent = isPersonalQuery ? null : parseLocalIntent(question); + if (fastIntent && fastIntent.tool !== 'plan_trip') { + try { + setStreamingText('🔍 Checking live data…'); + let fastResult: unknown; + switch (fastIntent.tool) { + case 'find_spots': + fastResult = await cvm.findSpots({ city: fastIntent.location, limit: 30 }); + break; + case 'find_events': + fastResult = await cvm.findEvents({ city: fastIntent.location, limit: 30 }); + break; + case 'find_coaches': + fastResult = await cvm.findCoaches({ location: fastIntent.location, limit: 30 }); + break; + case 'find_crews': + fastResult = await cvm.findCrews({ city: fastIntent.location, limit: 30 }); + break; + case 'find_shops': + fastResult = await cvm.findShops({ city: fastIntent.location, limit: 30 }); + break; + case 'find_tours': + fastResult = await cvm.findTours({ city: fastIntent.location, limit: 30 }); + break; + case 'find_gear': + fastResult = await cvm.findGear({ search: fastIntent.search, limit: 30 }); + break; + case 'get_community_stats': + fastResult = await cvm.getCommunityStats(); + break; + case 'get_weather': + fastResult = { content: [{ type: 'text', text: await fetchWeatherForCity(fastIntent.city) }] }; + break; + } + setCvmConnected(true); + setStreamingText(''); + appendMessage({ + role: 'sasquatch', + text: formatLocalResults(fastIntent, fastResult), + timestamp: Date.now(), + isLive: true, + }); + return; + } catch (fastErr) { + // Relays hiccuped — fall through to the AI path as a backup. + console.warn('[Sasquatch] fast-path failed, falling back to AI:', fastErr); + setStreamingText(''); + } + } + // 2. Build conversation history for AI const history = chatMessages.map((m) => ({ role: m.role === 'user' ? ('user' as const) : ('assistant' as const),