import { Agent, createStep, createWorkflow, scaleway } from "@ai_kit/core";
import { z } from "zod";
type WeatherInput = { city: string };
type WeatherSnapshot = {
location: string;
temperature: number;
feelsLike: number;
humidity: number;
windSpeed: number;
windGust: number;
conditions: string;
};
type AdviceOutput = { text: string };
type WorkflowMeta = Record<string, unknown>;
const weatherCodeLabels: Record<number, string> = {
0: "Ciel dégagé",
1: "Principalement dégagé",
2: "Nuages épars",
3: "Couvert",
45: "Brouillard",
48: "Brouillard givrants",
51: "Bruine légère",
53: "Bruine modérée",
55: "Bruine dense",
56: "Bruine verglaçante légère",
57: "Bruine verglaçante intense",
61: "Pluie légère",
63: "Pluie modérée",
65: "Pluie forte",
66: "Pluie verglaçante légère",
67: "Pluie verglaçante forte",
71: "Neige légère",
73: "Neige modérée",
75: "Neige forte",
77: "Grain de neige",
80: "Averses de pluie légères",
81: "Averses de pluie modérées",
82: "Averses de pluie violentes",
85: "Averses de neige légères",
86: "Averses de neige fortes",
95: "Orage léger",
96: "Orage avec grêle légère",
99: "Orage avec grêle forte",
};
const fetchWeather = createStep<WeatherInput, { forecast: WeatherSnapshot }>({
id: "fetch-weather",
description: "Récupère la météo courante via un service externe",
inputSchema: z.object({ city: z.string().min(1) }),
outputSchema: z.object({
location: z.string(),
temperature: z.number(),
feelsLike: z.number(),
humidity: z.number(),
windSpeed: z.number(),
windGust: z.number(),
conditions: z.string(),
}),
handler: async ({ input, signal }) => {
const response = await fetch(
`https://api.open-meteo.com/v1/forecast?current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code&timezone=Europe/Paris&hourly=temperature_2m&daily=weather_code&latitude=48.8566&longitude=2.3522`,
{ signal },
);
if (!response.ok) {
throw new Error(`Erreur sur l'API météo (${response.status})`);
}
const body = await response.json();
const current = body.current;
const snapshot: WeatherSnapshot = {
location: input.city,
temperature: current.temperature_2m,
feelsLike: current.apparent_temperature,
humidity: current.relative_humidity_2m,
windSpeed: current.wind_speed_10m,
windGust: current.wind_gusts_10m,
conditions:
weatherCodeLabels[current.weather_code as keyof typeof weatherCodeLabels] ??
"Conditions inconnues",
};
return { forecast: snapshot };
},
});
const generateAdvice = createStep<
{ forecast: WeatherSnapshot },
AdviceOutput,
WorkflowMeta
>({
id: "generate-advice",
description: "Produit un message conseils grâce à un agent",
handler: async ({ input, context }) => {
context.emit({
type: "forecast",
data: input.forecast,
});
const agent = new Agent({
name: "weather-advisor",
instructions:
"Tu es un assistant météo qui donne des conseils pratiques et un ton chaleureux.",
model: scaleway("gpt-oss-120b"),
});
const advice = await agent.generate({
prompt: `Ville: ${input.forecast.location}
Température ressentie: ${input.forecast.feelsLike}°C
Conditions: ${input.forecast.conditions}
Humidité: ${input.forecast.humidity}%
Vent: ${input.forecast.windSpeed} km/h (rafales ${input.forecast.windGust} km/h)
Propose un court message en français qui résume la météo et donne un conseil concret.`,
});
return { text: advice.text };
},
});
export const weatherAdvisorWorkflow = createWorkflow<
WeatherInput,
AdviceOutput,
WorkflowMeta
>({
id: "weather-advisor",
description: "Workflow de conseils météo piloté par un agent",
})
.then(fetchWeather)
.then(generateAdvice)
.commit();