Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion lib/agents/tools/geospatial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async function getConnectedMcpClient(): Promise<McpClient | null> {

let config;
try {
const mapboxMcpConfig = await import('QCX/mapbox_mcp_config.json');
const mapboxMcpConfig = await import('../../../mapbox_mcp_config.json');
config = {
...mapboxMcpConfig.default || mapboxMcpConfig,
mapboxAccessToken
Expand Down
31 changes: 26 additions & 5 deletions lib/agents/tools/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ 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 { mapboxGeocodingTool } from './mapbox/geocoding'
import { mapboxDirectionsTool } from './mapbox/directions'
import { mapboxMatrixTool } from './mapbox/matrix'
import { mapboxIsochroneTool } from './mapbox/isochrone'
import { mapboxStaticImageTool } from './mapbox/static-image'

export interface ToolProps {
uiStream: ReturnType<typeof createStreamableUI>
fullResponse: string
// mcp?: any; // Removed mcp property as it's no longer passed down for geospatialTool
}

// Removed mcp from parameters
export const getTools = ({ uiStream, fullResponse }: ToolProps) => {
const tools: any = {
search: searchTool({
Expand All @@ -21,10 +24,28 @@ export const getTools = ({ uiStream, fullResponse }: ToolProps) => {
uiStream,
fullResponse
}),
// geospatialTool now only requires uiStream
geospatialQueryTool: geospatialTool({
uiStream
// mcp: mcp || null // Removed mcp argument
}),
mapboxGeocoding: mapboxGeocodingTool({
uiStream,
fullResponse
}),
mapboxDirections: mapboxDirectionsTool({
uiStream,
fullResponse
}),
mapboxMatrix: mapboxMatrixTool({
uiStream,
fullResponse
}),
mapboxIsochrone: mapboxIsochroneTool({
uiStream,
fullResponse
}),
mapboxStaticImage: mapboxStaticImageTool({
uiStream,
fullResponse
})
}

Expand Down
77 changes: 77 additions & 0 deletions lib/agents/tools/mapbox/directions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { BotMessage } from '@/components/message'
import { Card } from '@/components/ui/card'
import { directionsSchema } from '@/lib/schema/mapbox'
import { getConnectedMcpClient, closeClient } from './mcp-client'
import { ToolProps } from '..'

export const mapboxDirectionsTool = ({ uiStream }: ToolProps) => ({
description: 'Get directions between two locations.',
parameters: directionsSchema,
execute: async ({
origin,
destination,
profile
}: {
origin: string
destination: string
profile: 'driving' | 'walking' | 'cycling'
}) => {
const uiFeedbackStream = createStreamableValue<string>()
uiStream.append(<BotMessage content={uiFeedbackStream.value} />)

uiFeedbackStream.update(
`Getting ${profile} directions from "${origin}" to "${destination}"...`
)

const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
const error =
'Mapbox tool is not available. Please check your configuration.'
uiFeedbackStream.update(error)
return { error }
}

let result
try {
const toolArgs = { origin, destination, profile }
const directionsResult = await mcpClient.callTool({
name: 'mapbox_directions',
arguments: toolArgs
})

const toolResults = (directionsResult as any)?.tool_results || []
if (toolResults.length === 0 || !toolResults[0]?.content) {
throw new Error('No content returned from mapping service')
}

let content = toolResults[0].content
if (typeof content === 'string') {
const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
const match = content.match(jsonRegex)
if (match) {
content = JSON.parse(match[1].trim())
} else {
content = JSON.parse(content)
}
}
result = content
} catch (error: any) {
console.error('Mapbox directions tool error:', error)
const errorMessage = `Error getting directions: ${error.message}`
uiFeedbackStream.update(errorMessage)
result = { error: errorMessage }
} finally {
await closeClient(mcpClient)
}

uiFeedbackStream.done()
uiStream.update(
<Card className="p-4 mt-2 text-sm">
<pre>{JSON.stringify(result, null, 2)}</pre>
</Card>
)

return result
}
})
73 changes: 73 additions & 0 deletions lib/agents/tools/mapbox/geocoding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { BotMessage } from '@/components/message'
import { Card } from '@/components/ui/card'
import { geocodingSchema } from '@/lib/schema/mapbox'
import { getConnectedMcpClient, closeClient } from './mcp-client'
import { ToolProps } from '..'

export const mapboxGeocodingTool = ({ uiStream }: ToolProps) => ({
description: 'Get coordinates for a location and optionally a map.',
parameters: geocodingSchema,
execute: async ({
query,
includeMap
}: {
query: string
includeMap: boolean
}) => {
const uiFeedbackStream = createStreamableValue<string>()
uiStream.append(<BotMessage content={uiFeedbackStream.value} />)

uiFeedbackStream.update(`Searching for "${query}"...`)

const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
const error =
'Mapbox tool is not available. Please check your configuration.'
uiFeedbackStream.update(error)
return { error }
}

let result
try {
const toolArgs = { query, includeMapPreview: includeMap }
const geocodeResult = await mcpClient.callTool({
name: 'mapbox_geocoding',
arguments: toolArgs
})

const toolResults = (geocodeResult as any)?.tool_results || []
if (toolResults.length === 0 || !toolResults[0]?.content) {
throw new Error('No content returned from mapping service')
}

let content = toolResults[0].content
if (typeof content === 'string') {
const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
const match = content.match(jsonRegex)
if (match) {
content = JSON.parse(match[1].trim())
} else {
content = JSON.parse(content)
}
}
result = content
} catch (error: any) {
console.error('Mapbox geocoding tool error:', error)
const errorMessage = `Error searching for "${query}": ${error.message}`
uiFeedbackStream.update(errorMessage)
result = { error: errorMessage }
} finally {
await closeClient(mcpClient)
}

uiFeedbackStream.done()
uiStream.update(
<Card className="p-4 mt-2 text-sm">
<pre>{JSON.stringify(result, null, 2)}</pre>
</Card>
)

return result
}
})
77 changes: 77 additions & 0 deletions lib/agents/tools/mapbox/isochrone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { BotMessage } from '@/components/message'
import { Card } from '@/components/ui/card'
import { isochroneSchema } from '@/lib/schema/mapbox'
import { getConnectedMcpClient, closeClient } from './mcp-client'
import { ToolProps } from '..'

export const mapboxIsochroneTool = ({ uiStream }: ToolProps) => ({
description: 'Generate isochrone polygons to show areas reachable within a certain time.',
parameters: isochroneSchema,
execute: async ({
location,
contour_minutes,
profile
}: {
location: string
contour_minutes: number
profile: 'driving' | 'walking' | 'cycling'
}) => {
const uiFeedbackStream = createStreamableValue<string>()
uiStream.append(<BotMessage content={uiFeedbackStream.value} />)

uiFeedbackStream.update(
`Generating ${contour_minutes}-minute isochrone for "${location}"...`
)

const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
const error =
'Mapbox tool is not available. Please check your configuration.'
uiFeedbackStream.update(error)
return { error }
}

let result
try {
const toolArgs = { location, contour_minutes, profile }
const isochroneResult = await mcpClient.callTool({
name: 'mapbox_isochrone',
arguments: toolArgs
})

const toolResults = (isochroneResult as any)?.tool_results || []
if (toolResults.length === 0 || !toolResults[0]?.content) {
throw new Error('No content returned from mapping service')
}

let content = toolResults[0].content
if (typeof content === 'string') {
const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
const match = content.match(jsonRegex)
if (match) {
content = JSON.parse(match[1].trim())
} else {
content = JSON.parse(content)
}
}
result = content
} catch (error: any) {
console.error('Mapbox isochrone tool error:', error)
const errorMessage = `Error generating isochrone: ${error.message}`
uiFeedbackStream.update(errorMessage)
result = { error: errorMessage }
} finally {
await closeClient(mcpClient)
}

uiFeedbackStream.done()
uiStream.update(
<Card className="p-4 mt-2 text-sm">
<pre>{JSON.stringify(result, null, 2)}</pre>
</Card>
)

return result
}
})
77 changes: 77 additions & 0 deletions lib/agents/tools/mapbox/matrix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { BotMessage } from '@/components/message'
import { Card } from '@/components/ui/card'
import { matrixSchema } from '@/lib/schema/mapbox'
import { getConnectedMcpClient, closeClient } from './mcp-client'
import { ToolProps } from '..'

export const mapboxMatrixTool = ({ uiStream }: ToolProps) => ({
description: 'Calculate travel times between multiple origins and destinations.',
parameters: matrixSchema,
execute: async ({
origins,
destinations,
profile
}: {
origins: string[]
destinations: string[]
profile: 'driving' | 'walking' | 'cycling'
}) => {
const uiFeedbackStream = createStreamableValue<string>()
uiStream.append(<BotMessage content={uiFeedbackStream.value} />)

uiFeedbackStream.update(
`Calculating travel times for ${origins.length} origins to ${destinations.length} destinations...`
)

const mcpClient = await getConnectedMcpClient()
if (!mcpClient) {
const error =
'Mapbox tool is not available. Please check your configuration.'
uiFeedbackStream.update(error)
return { error }
}

let result
try {
const toolArgs = { origins, destinations, profile }
const matrixResult = await mcpClient.callTool({
name: 'mapbox_matrix',
arguments: toolArgs
})

const toolResults = (matrixResult as any)?.tool_results || []
if (toolResults.length === 0 || !toolResults[0]?.content) {
throw new Error('No content returned from mapping service')
}

let content = toolResults[0].content
if (typeof content === 'string') {
const jsonRegex = /```(?:json)?\n?([\s\S]*?)\n?```/
const match = content.match(jsonRegex)
if (match) {
content = JSON.parse(match[1].trim())
} else {
content = JSON.parse(content)
}
}
result = content
} catch (error: any) {
console.error('Mapbox matrix tool error:', error)
const errorMessage = `Error calculating travel times: ${error.message}`
uiFeedbackStream.update(errorMessage)
result = { error: errorMessage }
} finally {
await closeClient(mcpClient)
}

uiFeedbackStream.done()
uiStream.update(
<Card className="p-4 mt-2 text-sm">
<pre>{JSON.stringify(result, null, 2)}</pre>
</Card>
)

return result
}
})
Loading