Skip to content

Commit 914ba7d

Browse files
committed
feat: add weather plugin with notification channel and example usage
1 parent cc33654 commit 914ba7d

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

examples/plugin_system.exs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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)

test/agent_forge/examples_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,24 @@ defmodule AgentForge.ExamplesTest do
6868
assert output =~ "- Completed: true"
6969
end
7070
end
71+
72+
describe "plugin_system.exs" do
73+
test "demonstrates plugin system functionality" do
74+
output = capture_io(fn -> Code.eval_file("examples/plugin_system.exs") end)
75+
76+
# Verify plugin initialization
77+
assert output =~ "Initializing Weather Plugin"
78+
79+
# Verify plugin tool usage
80+
assert output =~ "Checking weather for: San Francisco"
81+
assert output =~ "Current conditions:"
82+
83+
# Verify notification channel functionality
84+
assert output =~ "[Weather Alert - high] Extreme heat warning for Sahara Desert"
85+
86+
# Verify plugin metadata listing
87+
assert output =~ "Loaded Plugins:"
88+
assert output =~ "Weather Plugin v1.0.0: Provides weather forecast functionality"
89+
end
90+
end
7191
end

0 commit comments

Comments
 (0)