|
| 1 | +defmodule WeatherPlugin do |
| 2 | + @moduledoc """ |
| 3 | + Example plugin that provides weather forecast functionality. |
| 4 | + """ |
| 5 | + @behaviour AgentForge.Plugin |
| 6 | + |
| 7 | + @impl true |
| 8 | + def init(_opts) do |
| 9 | + # In a real plugin, we might initialize connections or load configs |
| 10 | + # No IO.puts here, we'll print it in the main program flow |
| 11 | + :ok |
| 12 | + end |
| 13 | + |
| 14 | + @impl true |
| 15 | + def register_tools(registry) do |
| 16 | + registry.register("get_forecast", &forecast/1) |
| 17 | + :ok |
| 18 | + end |
| 19 | + |
| 20 | + @impl true |
| 21 | + def register_primitives do |
| 22 | + # This plugin doesn't add any primitives |
| 23 | + :ok |
| 24 | + end |
| 25 | + |
| 26 | + @impl true |
| 27 | + def register_channels do |
| 28 | + AgentForge.Notification.Registry.register_channel(WeatherNotificationChannel) |
| 29 | + :ok |
| 30 | + end |
| 31 | + |
| 32 | + @impl true |
| 33 | + def metadata do |
| 34 | + %{ |
| 35 | + name: "Weather Plugin", |
| 36 | + version: "1.0.0", |
| 37 | + description: "Provides weather forecast functionality", |
| 38 | + author: "AgentForge Team", |
| 39 | + compatible_versions: ">= 0.1.0" |
| 40 | + } |
| 41 | + end |
| 42 | + |
| 43 | + # Tool implementation |
| 44 | + defp forecast(params) do |
| 45 | + location = Map.get(params, "location", "Unknown") |
| 46 | + # In a real plugin, this would make an API call to a weather service |
| 47 | + # For this example, we just return mock data |
| 48 | + %{ |
| 49 | + location: location, |
| 50 | + temperature: 22, |
| 51 | + conditions: "Sunny", |
| 52 | + forecast: [ |
| 53 | + %{day: "Today", high: 24, low: 18, conditions: "Sunny"}, |
| 54 | + %{day: "Tomorrow", high: 22, low: 17, conditions: "Partly Cloudy"} |
| 55 | + ] |
| 56 | + } |
| 57 | + end |
| 58 | +end |
| 59 | + |
| 60 | +defmodule WeatherNotificationChannel do |
| 61 | + @moduledoc """ |
| 62 | + Example notification channel for weather alerts. |
| 63 | + """ |
| 64 | + @behaviour AgentForge.Notification.Channel |
| 65 | + |
| 66 | + @impl true |
| 67 | + def name, do: :weather_alert |
| 68 | + |
| 69 | + @impl true |
| 70 | + def send(message, config) do |
| 71 | + priority = Map.get(config, :priority, "normal") |
| 72 | + # Remove quotes from message to match expected test format |
| 73 | + clean_message = message |> String.replace("\"", "") |
| 74 | + IO.puts("[Weather Alert - #{priority}] #{clean_message}") |
| 75 | + :ok |
| 76 | + end |
| 77 | +end |
| 78 | + |
| 79 | +# Start necessary processes |
| 80 | +_registry_pid = case AgentForge.Notification.Registry.start_link([]) do |
| 81 | + {:ok, pid} -> pid |
| 82 | + {:error, {:already_started, pid}} -> pid |
| 83 | +end |
| 84 | + |
| 85 | +_plugin_manager_pid = case AgentForge.PluginManager.start_link([]) do |
| 86 | + {:ok, pid} -> pid |
| 87 | + {:error, {:already_started, pid}} -> pid |
| 88 | +end |
| 89 | + |
| 90 | +_tools_pid = case AgentForge.Tools.start_link([]) do |
| 91 | + {:ok, pid} -> pid |
| 92 | + {:error, {:already_started, pid}} -> pid |
| 93 | +end |
| 94 | + |
| 95 | +# Load the weather plugin |
| 96 | +IO.puts("Initializing Weather Plugin") |
| 97 | +:ok = AgentForge.PluginManager.load_plugin(WeatherPlugin) |
| 98 | + |
| 99 | +# Define a simple flow that uses the weather plugin |
| 100 | +process_weather = fn signal, state -> |
| 101 | + location = signal.data |
| 102 | + |
| 103 | + # Use the plugin tool to get weather forecast |
| 104 | + {:ok, forecast_tool} = AgentForge.Tools.get("get_forecast") |
| 105 | + forecast = forecast_tool.(%{"location" => location}) |
| 106 | + |
| 107 | + # Emit a notification for extreme temperatures |
| 108 | + if forecast.temperature > 30 do |
| 109 | + notify = AgentForge.Primitives.notify( |
| 110 | + [:weather_alert], |
| 111 | + config: %{weather_alert: %{priority: "high"}} |
| 112 | + ) |
| 113 | + |
| 114 | + alert_signal = AgentForge.Signal.new(:alert, "Extreme heat warning for #{location}") |
| 115 | + notify.(alert_signal, state) |
| 116 | + end |
| 117 | + |
| 118 | + # Return the forecast data |
| 119 | + {{:emit, forecast}, state} |
| 120 | +end |
| 121 | + |
| 122 | +# Create and execute a simple flow with a list of handlers |
| 123 | +flow = [process_weather] |
| 124 | + |
| 125 | +# Run the flow with different locations |
| 126 | +locations = ["San Francisco", "Tokyo", "Sahara Desert"] |
| 127 | + |
| 128 | +Enum.each(locations, fn location -> |
| 129 | + signal = AgentForge.Signal.new(:location, location) |
| 130 | + IO.puts("\nChecking weather for: #{location}") |
| 131 | + {:ok, result, _state} = AgentForge.Flow.process(flow, signal, %{}) |
| 132 | + IO.puts("Current conditions: #{result.temperature}°C, #{result.conditions}") |
| 133 | + |
| 134 | + # For demo purposes, simulate a high temperature for Sahara Desert |
| 135 | + if location == "Sahara Desert" do |
| 136 | + hot_signal = AgentForge.Signal.new(:location, location) |
| 137 | + # Monkey patch the forecast tool temporarily to return extreme temperature |
| 138 | + {:ok, old_fn} = AgentForge.Tools.get("get_forecast") |
| 139 | + |
| 140 | + AgentForge.Tools.register("get_forecast", fn params -> |
| 141 | + result = old_fn.(params) |
| 142 | + Map.put(result, :temperature, 45) |
| 143 | + end) |
| 144 | + |
| 145 | + {:ok, _result, _state} = AgentForge.Flow.process(flow, hot_signal, %{}) |
| 146 | + |
| 147 | + # Restore original function |
| 148 | + AgentForge.Tools.register("get_forecast", old_fn) |
| 149 | + end |
| 150 | +end) |
| 151 | + |
| 152 | +# List all loaded plugins and their metadata |
| 153 | +plugins = AgentForge.PluginManager.list_plugins() |
| 154 | +IO.puts("\nLoaded Plugins:") |
| 155 | +Enum.each(plugins, fn {_module, metadata} -> |
| 156 | + IO.puts("- #{metadata.name} v#{metadata.version}: #{metadata.description}") |
| 157 | +end) |
0 commit comments