diff --git a/app/actions.tsx b/app/actions.tsx index f3b3c44f..37411a7b 100644 --- a/app/actions.tsx +++ b/app/actions.tsx @@ -63,6 +63,9 @@ async function submit(formData?: FormData, skip?: boolean) { ? `{"action": "skip"}` : (formData?.get('input') as string); + const mapDataString = formData?.get('map_data') as string | undefined; + const mapData = mapDataString ? JSON.parse(mapDataString) : undefined; + const content = skip ? userInput : formData @@ -149,7 +152,7 @@ async function submit(formData?: FormData, skip?: boolean) { uiStream, streamText, messages, - // mcp, // mcp instance is no longer passed down + mapData, // Pass mapData here useSpecificAPI ); answer = fullResponse; diff --git a/components/chat-panel.tsx b/components/chat-panel.tsx index c83f4445..83768720 100644 --- a/components/chat-panel.tsx +++ b/components/chat-panel.tsx @@ -4,6 +4,7 @@ import { useEffect, useState, useRef } from 'react' import { useRouter } from 'next/navigation' import type { AI, UIState } from '@/app/actions' import { useUIState, useActions } from 'ai/rsc' +import { useMapData } from './map/map-data-context' // Removed import of useGeospatialToolMcp as it's no longer used/available import { cn } from '@/lib/utils' import { UserMessage } from './user-message' @@ -21,6 +22,7 @@ interface ChatPanelProps { export function ChatPanel({ messages, input, setInput }: ChatPanelProps) { const [, setMessages] = useUIState() const { submit } = useActions() + const { mapData } = useMapData() // Removed mcp instance as it's no longer passed to submit const [isButtonPressed, setIsButtonPressed] = useState(false) const [isMobile, setIsMobile] = useState(false) @@ -58,6 +60,9 @@ export function ChatPanel({ messages, input, setInput }: ChatPanelProps) { } ]) const formData = new FormData(e.currentTarget) + if (mapData) { + formData.append('map_data', JSON.stringify(mapData)) + } // Removed mcp argument from submit call const responseMessage = await submit(formData) setMessages(currentMessages => [...currentMessages, responseMessage as any]) diff --git a/components/map/map-data-context.tsx b/components/map/map-data-context.tsx index 149cb36b..bb41ca0e 100644 --- a/components/map/map-data-context.tsx +++ b/components/map/map-data-context.tsx @@ -14,6 +14,9 @@ export interface MapData { measurement: string; geometry: any; }>; + center?: [number, number]; + zoom?: number; + pitch?: number; } interface MapDataContextType { diff --git a/components/map/mapbox-map.tsx b/components/map/mapbox-map.tsx index 3f2d5f2b..89473a96 100644 --- a/components/map/mapbox-map.tsx +++ b/components/map/mapbox-map.tsx @@ -318,9 +318,16 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number const center = map.current.getCenter(); const zoom = map.current.getZoom(); const pitch = map.current.getPitch(); - currentMapCenterRef.current = { center: [center.lng, center.lat], zoom, pitch }; + const newCenter: [number, number] = [center.lng, center.lat]; + currentMapCenterRef.current = { center: newCenter, zoom, pitch }; + setMapData(prevData => ({ + ...prevData, + center: newCenter, + zoom: zoom, + pitch: pitch, + })); } - }, []) + }, [setMapData]) // Set up idle rotation checker useEffect(() => { diff --git a/lib/agents/researcher.tsx b/lib/agents/researcher.tsx index 6ef6d53b..fb235ebf 100644 --- a/lib/agents/researcher.tsx +++ b/lib/agents/researcher.tsx @@ -11,12 +11,14 @@ import { BotMessage } from '@/components/message' import { getTools } from './tools' import { getModel } from '../utils' +import { MapData } from '@/components/map/map-data-context' + export async function researcher( dynamicSystemPrompt: string, // New parameter uiStream: ReturnType, streamText: ReturnType>, messages: CoreMessage[], - // mcp: any, // Removed mcp parameter + mapData: MapData | undefined, // Add mapData parameter useSpecificModel?: boolean ) { let fullResponse = '' @@ -28,11 +30,24 @@ export async function researcher( ) const currentDate = new Date().toLocaleString() + let mapContext = ''; + if (mapData) { + mapContext += 'The user is currently viewing a map with the following properties:\n'; + if (mapData.center) { + mapContext += `- Center: [${mapData.center.join(', ')}]\n`; + } + if (mapData.zoom) { + mapContext += `- Zoom level: ${mapData.zoom}\n`; + } + if (mapData.drawnFeatures && mapData.drawnFeatures.length > 0) { + mapContext += `- Drawn features on map: ${JSON.stringify(mapData.drawnFeatures.map(f => ({ type: f.type, measurement: f.measurement })))} \n`; + } + } // Default system prompt, used if dynamicSystemPrompt is not provided const default_system_prompt = `As a comprehensive AI assistant, you can search the web, retrieve information from URLs, and understand geospatial queries to assist the user and display information on a map. Current date and time: ${currentDate}. -Tool Usage Guide: +${mapContext}Tool Usage Guide: - For general web searches for factual information: Use the 'search' tool. - For retrieving content from specific URLs provided by the user: Use the 'retrieve' tool. (Do not use this for URLs found in search results). - **For any questions involving locations, places, addresses, geographical features, finding businesses or points of interest, distances between locations, or directions: You MUST use the 'geospatialQueryTool'. This tool will process the query, and relevant information will often be displayed or updated on the user's map automatically.** @@ -56,7 +71,7 @@ Match the language of your response to the user's language.`; tools: getTools({ uiStream, fullResponse, - // mcp // mcp parameter is no longer passed to getTools + mapData }) }) diff --git a/lib/agents/tools/geospatial.tsx b/lib/agents/tools/geospatial.tsx index cb1ff07c..eb0a2b93 100644 --- a/lib/agents/tools/geospatial.tsx +++ b/lib/agents/tools/geospatial.tsx @@ -2,6 +2,7 @@ * Fixed geospatial tool with improved error handling and schema */ import { createStreamableUI, createStreamableValue } from 'ai/rsc'; +import { MapData } from '@/components/map/map-data-context'; import { BotMessage } from '@/components/message'; import { geospatialQuerySchema } from '@/lib/schema/geospatial'; import { Client as MCPClientClass } from '@modelcontextprotocol/sdk/client/index.js'; @@ -141,7 +142,7 @@ async function closeClient(client: McpClient | null) { /** * Main geospatial tool executor. */ -export const geospatialTool = ({ uiStream }: { uiStream: ReturnType }) => ({ +export const geospatialTool = ({ uiStream, mapData }: { uiStream: ReturnType, mapData?: MapData }) => ({ description: `Use this tool for location-based queries including: - Finding specific places, addresses, or landmarks - Getting coordinates for locations diff --git a/lib/agents/tools/index.tsx b/lib/agents/tools/index.tsx index 4c08f373..7e6a6cd1 100644 --- a/lib/agents/tools/index.tsx +++ b/lib/agents/tools/index.tsx @@ -2,16 +2,16 @@ import { createStreamableUI } from 'ai/rsc' import { retrieveTool } from './retrieve' import { searchTool } from './search' import { videoSearchTool } from './video-search' -import { geospatialTool } from './geospatial' // Removed useGeospatialToolMcp import +import { geospatialTool } from './geospatial' +import { MapData } from '@/components/map/map-data-context' export interface ToolProps { uiStream: ReturnType fullResponse: string - // mcp?: any; // Removed mcp property as it's no longer passed down for geospatialTool + mapData?: MapData } -// Removed mcp from parameters -export const getTools = ({ uiStream, fullResponse }: ToolProps) => { +export const getTools = ({ uiStream, fullResponse, mapData }: ToolProps) => { const tools: any = { search: searchTool({ uiStream, @@ -21,10 +21,9 @@ export const getTools = ({ uiStream, fullResponse }: ToolProps) => { uiStream, fullResponse }), - // geospatialTool now only requires uiStream geospatialQueryTool: geospatialTool({ - uiStream - // mcp: mcp || null // Removed mcp argument + uiStream, + mapData }) }