feat: faster variant switching, live Grok thoughts, accurate trip endpoints

- Bump z-index on vehicle selector and modals (z-50 sat below Leaflet panes)
- Prefetch the other route variants in the background as soon as the first
  trip lands; switching now hits the cache and is near-instant
- Surface Grok's streaming thoughts to the UI: glassy overlay on the empty
  map + sidebar callout, with skeleton shimmer until the first thought
- Thread explicit origin/destination from the TopBar through to the prompt
  as a ground-truth block; harden rules so the first/last stops match the
  user's actual endpoints and cross-Channel trips include both sides
This commit is contained in:
2026-05-31 17:14:04 +01:00
parent ed64712525
commit 88fc86dc32
3 changed files with 226 additions and 51 deletions
+8 -2
View File
@@ -13,6 +13,8 @@ const ChatRequestSchema = z.object({
itinerary: z.any().optional(),
history: z.array(z.object({ role: z.enum(['user', 'assistant']), content: z.string() })).optional(),
selectedVariant: z.enum(['fast', 'scenic', 'cheap']).optional(),
origin: z.string().optional(),
destination: z.string().optional(),
});
router.post('/chat', async (req, res) => {
@@ -28,7 +30,7 @@ router.post('/chat', async (req, res) => {
return res.status(400).json({ error: 'Invalid request' });
}
const { message, vehicle, itinerary, history = [], selectedVariant = 'fast' } = parsed.data;
const { message, vehicle, itinerary, history = [], selectedVariant = 'fast', origin, destination } = parsed.data;
log.info({
requestId,
@@ -37,6 +39,8 @@ router.post('/chat', async (req, res) => {
historyLength: history.length,
currentItineraryDays: itinerary?.days?.length || 0,
selectedVariant,
origin,
destination,
}, 'Parsed chat request');
// Call Grok (this will produce very detailed logs inside GrokHeadlessClient)
@@ -45,6 +49,7 @@ router.post('/chat', async (req, res) => {
itinerary,
vehicle,
selectedVariant,
{ origin, destination },
);
const duration = Date.now() - start;
@@ -86,7 +91,7 @@ router.post('/chat/stream', async (req, res) => {
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid request', issues: parsed.error.format() });
}
const { message, vehicle, itinerary, history = [], selectedVariant = 'fast' } = parsed.data;
const { message, vehicle, itinerary, history = [], selectedVariant = 'fast', origin, destination } = parsed.data;
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache, no-transform');
@@ -119,6 +124,7 @@ router.post('/chat/stream', async (req, res) => {
itinerary,
vehicle,
selectedVariant,
{ origin, destination },
);
for await (const ev of stream) {
if (cancelled) break;