AgentForge (AgentForge v0.2.2)

View Source

AgentForge is a lightweight, signal-driven workflow framework designed for personal projects.

Key Features

  • Signal-based communication
  • Composable handler pipelines
  • Persistent state management
  • Debug tracing support

Example

# Define a simple handler
message_handler = fn signal, state ->
  new_state = Map.put(state, :last_message, signal.data)
  {AgentForge.Signal.emit(:processed, "Got: #{signal.data}"), new_state}
end

# Create a flow with the handler
flow = AgentForge.new_flow([message_handler], debug: true)

# Execute the flow with a signal
{:ok, result, _state} = flow.(AgentForge.Signal.new(:message, "Hello"))
# result.data will be "Got: Hello"

Summary

Functions

Gets statistics from the last flow execution. Returns nil if no flow has been executed yet or statistics collection was disabled.

Creates a new flow with the given handlers and options. Returns a function that can be used to execute the flow.

Creates a new stateful flow that maintains state between executions. Similar to new_flow/2 but automatically stores and retrieves state.

Processes a flow with execution limits. This can prevent long-running operations.

Functions

emit(type, data, meta \\ %{})

See AgentForge.Signal.emit/3.

emit_many(signals)

See AgentForge.Signal.emit_many/1.

get_last_execution_stats()

Gets statistics from the last flow execution. Returns nil if no flow has been executed yet or statistics collection was disabled.

Examples

iex> handlers = [fn signal, state -> {{:emit, signal}, state} end]
iex> signal = AgentForge.Signal.new(:test, "data")
iex> {:ok, _, _} = AgentForge.process_with_limits(handlers, signal, %{})
iex> stats = AgentForge.get_last_execution_stats()
iex> stats.steps
1

halt(value)

See AgentForge.Signal.halt/1.

new_flow(handlers, opts \\ [])

Creates a new flow with the given handlers and options. Returns a function that can be used to execute the flow.

Options

All options from AgentForge.Runtime.execute/3 are supported.

Examples

iex> handler = fn signal, state ->
...>   {AgentForge.Signal.emit(:echo, signal.data), state}
...> end
iex> flow = AgentForge.new_flow([handler])
iex> {:ok, result, _} = flow.(AgentForge.Signal.new(:test, "hello"))
iex> result.data
"hello"

new_signal(type, data, meta \\ %{})

See AgentForge.Signal.new/3.

new_stateful_flow(handlers, opts \\ [])

Creates a new stateful flow that maintains state between executions. Similar to new_flow/2 but automatically stores and retrieves state.

Examples

iex> {:ok, _pid} = AgentForge.Store.start_link(name: :test_store)
iex> counter = fn _signal, state ->
...>   count = Map.get(state, :count, 0) + 1
...>   {AgentForge.Signal.emit(:count, count), Map.put(state, :count, count)}
...> end
iex> flow = AgentForge.new_stateful_flow([counter], store_name: :test_store)
iex> {:ok, result1, _} = flow.(AgentForge.Signal.new(:inc, nil))
iex> {:ok, result2, _} = flow.(AgentForge.Signal.new(:inc, nil))
iex> result2.data > result1.data
true

process_with_limits(handlers, signal, initial_state, opts \\ [])

@spec process_with_limits(
  [function()],
  AgentForge.Signal.t(),
  map(),
  keyword()
) ::
  {:ok, AgentForge.Signal.t() | term(), term()}
  | {:ok, AgentForge.Signal.t() | term(), term(), AgentForge.ExecutionStats.t()}
  | {:error, term(), term()}
  | {:error, term(), term(), AgentForge.ExecutionStats.t()}

Processes a flow with execution limits. This can prevent long-running operations.

Options

  • :timeout_ms - Maximum execution time in milliseconds (default: 30000)
  • :collect_stats - Whether to collect execution statistics (default: true)
  • :return_stats - Whether to return statistics in the result (default: false)

Examples

iex> handlers = [
...>   fn _signal, state -> {{:emit, AgentForge.Signal.new(:done, "Success")}, state} end
...> ]
iex> {:ok, result, _} = AgentForge.process_with_limits(handlers, AgentForge.Signal.new(:test, "data"), %{})
iex> result.data
"Success"