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),