Skip to content

add mastra #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
3 changes: 2 additions & 1 deletion apps/web/client/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
CSB_API_KEY=
CSB_API_KEY=
ANTHROPIC_API_KEY=
30 changes: 16 additions & 14 deletions apps/web/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,20 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@codemirror/lang-javascript": "^6.2.3",
"@ai-sdk/anthropic": "^1.2.10",
"@codemirror/lang-css": "^6.2.0",
"@codemirror/lang-html": "^6.4.7",
"@codemirror/lang-javascript": "^6.2.3",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.1.7",
"@codesandbox/sdk": "^0.11.1",
"@mastra/core": "^0.9.0",
"@onlook/constants": "*",
"@onlook/fonts": "*",
"@onlook/models": "*",
"@onlook/parser": "*",
"@onlook/penpal": "*",
"@onlook/rpc": "*",
"@onlook/ui": "*",
"@radix-ui/react-slot": "^1.1.2",
"@supabase/ssr": "^0.6.1",
Expand All @@ -44,13 +50,14 @@
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"class-variance-authority": "^0.7.1",
"@uiw/codemirror-extensions-basic-setup": "^4.23.10",
"@uiw/react-codemirror": "^4.23.10",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"localforage": "^1.10.0",
"lucide-react": "^0.486.0",
"mime-lite": "^1.0.3",
"mobx-react-lite": "^4.1.0",
"motion": "^12.6.3",
"next": "^15.2.3",
Expand All @@ -60,24 +67,19 @@
"prosemirror-history": "^1.4.1",
"prosemirror-keymap": "^1.2.2",
"react": "^19.0.0",
"react-arborist": "^3.4.3",
"react-codemirror-merge": "4.23.10",
"react-dom": "^19.0.0",
"react-hotkeys-hook": "^5.0.1",
"react-codemirror-merge": "4.23.10",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"server-only": "^0.0.1",
"shiki": "^3.2.2",
"superjson": "^2.2.1",
"tailwind-merge": "^3.2.0",
"tw-animate-css": "^1.2.5",
"zod": "^3.24.2",
"@onlook/rpc": "*",
"@onlook/penpal": "*",
"@onlook/models": "*",
"@onlook/parser": "*",
"mime-lite": "^1.0.3",
"react-arborist": "^3.4.3",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"shiki": "^3.2.2",
"use-resize-observer": "^9.1.0"
"use-resize-observer": "^9.1.0",
"zod": "^3.24.2"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
Expand Down
21 changes: 21 additions & 0 deletions apps/web/client/src/mastra/agents/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { anthropic } from '@ai-sdk/anthropic';
import { Agent } from '@mastra/core/agent';
import { weatherTool } from '../tools';

export const weatherAgent = new Agent({
name: 'Weather Agent',
instructions: `
You are a helpful weather assistant that provides accurate weather information.
Your primary function is to help users get weather details for specific locations. When responding:
- Always ask for a location if none is provided
- If the location name isn’t in English, please translate it
- If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York")
- Include relevant details like humidity, wind conditions, and precipitation
- Keep responses concise but informative
Use the weatherTool to fetch current weather data.
`,
model: anthropic('claude-3-5-sonnet-20241022'),
tools: { weatherTool },
});
14 changes: 14 additions & 0 deletions apps/web/client/src/mastra/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import { Mastra } from '@mastra/core/mastra';
import { createLogger } from '@mastra/core/logger';
import { weatherWorkflow } from './workflows';
import { weatherAgent } from './agents';

export const mastra = new Mastra({
workflows: { weatherWorkflow },
agents: { weatherAgent },
logger: createLogger({
name: 'Mastra',
level: 'info',
}),
});
102 changes: 102 additions & 0 deletions apps/web/client/src/mastra/tools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

interface GeocodingResponse {
results: {
latitude: number;
longitude: number;
name: string;
}[];
}
interface WeatherResponse {
current: {
time: string;
temperature_2m: number;
apparent_temperature: number;
relative_humidity_2m: number;
wind_speed_10m: number;
wind_gusts_10m: number;
weather_code: number;
};
}

export const weatherTool = createTool({
id: 'get-weather',
description: 'Get current weather for a location',
inputSchema: z.object({
location: z.string().describe('City name'),
}),
outputSchema: z.object({
temperature: z.number(),
feelsLike: z.number(),
humidity: z.number(),
windSpeed: z.number(),
windGust: z.number(),
conditions: z.string(),
location: z.string(),
}),
execute: async ({ context }) => {
return await getWeather(context.location);
},
});

const getWeather = async (location: string) => {
const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`;
const geocodingResponse = await fetch(geocodingUrl);
const geocodingData = (await geocodingResponse.json()) as GeocodingResponse;

if (!geocodingData.results?.[0]) {
throw new Error(`Location '${location}' not found`);
}

const { latitude, longitude, name } = geocodingData.results[0];

const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`;

const response = await fetch(weatherUrl);
const data = (await response.json()) as WeatherResponse;

return {
temperature: data.current.temperature_2m,
feelsLike: data.current.apparent_temperature,
humidity: data.current.relative_humidity_2m,
windSpeed: data.current.wind_speed_10m,
windGust: data.current.wind_gusts_10m,
conditions: getWeatherCondition(data.current.weather_code),
location: name,
};
};

function getWeatherCondition(code: number): string {
const conditions: Record<number, string> = {
0: 'Clear sky',
1: 'Mainly clear',
2: 'Partly cloudy',
3: 'Overcast',
45: 'Foggy',
48: 'Depositing rime fog',
51: 'Light drizzle',
53: 'Moderate drizzle',
55: 'Dense drizzle',
56: 'Light freezing drizzle',
57: 'Dense freezing drizzle',
61: 'Slight rain',
63: 'Moderate rain',
65: 'Heavy rain',
66: 'Light freezing rain',
67: 'Heavy freezing rain',
71: 'Slight snow fall',
73: 'Moderate snow fall',
75: 'Heavy snow fall',
77: 'Snow grains',
80: 'Slight rain showers',
81: 'Moderate rain showers',
82: 'Violent rain showers',
85: 'Slight snow showers',
86: 'Heavy snow showers',
95: 'Thunderstorm',
96: 'Thunderstorm with slight hail',
99: 'Thunderstorm with heavy hail',
};
return conditions[code] || 'Unknown';
}
Loading