Helper functions for creating StateOps in Jido.AI strategies.
This module provides convenient helpers for common state operation patterns
used across strategies. It wraps Jido.Agent.StateOp constructors with
strategy-specific semantics.
StateOp Types
SetState- Deep merge attributes into stateSetPath- Set value at nested pathDeleteKeys- Remove top-level keysDeletePath- Delete value at nested path
Usage
state_ops = [
Helpers.set_strategy_status(:running),
Helpers.increment_iteration(),
Helpers.append_to_conversation(message)
]
Summary
Functions
Builds normalized context for plugin-routed action execution.
Creates a StateOp to add a pending tool call.
Creates a StateOp to append a message to the conversation.
Creates a StateOp to append to the streaming text.
Applies state operations to a state map.
Creates a StateOp to clear the current LLM call ID.
Creates a StateOp to clear pending tool calls.
Composes multiple state operations into a single list.
Creates a StateOp to delete specific keys from strategy state.
Creates a StateOp to delete temporary keys from strategy state.
Executes a non-strategy Jido.Action instruction using direct strategy semantics.
Executes an instruction if its action is a loadable module implementing run/2.
Creates a StateOp to prepend a message to the conversation.
Creates a StateOp to remove a specific pending tool by ID.
Creates a StateOp to reset the strategy state to initial values.
Creates a StateOp to set the current LLM call ID.
Creates a StateOp to set a specific config field.
Creates a StateOp to set the entire conversation.
Creates a StateOp to set the final answer.
Creates a StateOp to increment the iteration counter.
Creates a StateOp to set the iteration status.
Creates a StateOp to set pending tool calls.
Creates a StateOp to set a specific field in the strategy state.
Creates a StateOp to set the streaming text.
Creates a StateOp to set the termination reason.
Creates a StateOp to set the usage metadata.
Creates a StateOp to update the config field in strategy state.
Creates StateOps to update multiple config fields at once.
Creates a StateOp to update the strategy state.
Creates StateOps to update tools, actions_by_name, and reqllm_tools together.
Types
@type state_op() :: Jido.Agent.StateOp.SetState.t() | Jido.Agent.StateOp.SetPath.t() | Jido.Agent.StateOp.DeleteKeys.t() | Jido.Agent.StateOp.DeletePath.t()
@type strategy_ctx() :: map()
Functions
@spec action_context(Jido.Agent.t(), strategy_ctx()) :: map()
Builds normalized context for plugin-routed action execution.
Guarantees the state, agent, and plugin_state keys are present.
@spec add_pending_tool(map()) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to add a pending tool call.
Examples
iex> tool = %{id: "call_1", name: "search", arguments: %{query: "test"}}
iex> Helpers.add_pending_tool(tool)
%Jido.Agent.StateOp.SetState{attrs: %{pending_tool_calls: [%{id: "call_1", name: "search", arguments: %{query: "test"}}]}}
@spec append_conversation([map()]) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to append a message to the conversation.
Examples
iex> message = %{role: :user, content: "Hello"}
iex> Helpers.append_conversation([message])
%Jido.Agent.StateOp.SetState{attrs: %{conversation: [%{role: :user, content: "Hello"}]}}
@spec append_streaming_text(String.t()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to append to the streaming text.
Examples
iex> Helpers.append_streaming_text(" world")
%Jido.Agent.StateOp.SetPath{path: [:streaming_text], value: " world"}
Applies state operations to a state map.
This is useful for strategies to apply state operations internally before setting the strategy state on the agent.
Examples
iex> ops = [Jido.Agent.StateOp.set_path([:status], :running)]
iex> Helpers.apply_to_state(%{iteration: 1}, ops)
%{iteration: 1, status: :running}
@spec clear_call_id() :: Jido.Agent.StateOp.DeletePath.t()
Creates a StateOp to clear the current LLM call ID.
Examples
iex> Helpers.clear_call_id()
%Jido.Agent.StateOp.DeletePath{path: [:current_llm_call_id]}
@spec clear_pending_tools() :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to clear pending tool calls.
Examples
iex> Helpers.clear_pending_tools()
%Jido.Agent.StateOp.SetState{attrs: %{pending_tool_calls: []}}
Composes multiple state operations into a single list.
This is a convenience function for building state operation lists.
Examples
iex> Helpers.compose([
...> Helpers.set_iteration_status(:running),
...> Helpers.set_iteration(1)
...> ])
[%Jido.Agent.StateOp.SetPath{path: [:status], value: :running}, %Jido.Agent.StateOp.SetPath{path: [:iteration], value: 1}]
@spec delete_keys([atom()]) :: Jido.Agent.StateOp.DeleteKeys.t()
Creates a StateOp to delete specific keys from strategy state.
Examples
iex> Helpers.delete_keys([:temp1, :temp2])
%Jido.Agent.StateOp.DeleteKeys{keys: [:temp1, :temp2]}
@spec delete_temp_keys() :: Jido.Agent.StateOp.DeleteKeys.t()
Creates a StateOp to delete temporary keys from strategy state.
Examples
iex> Helpers.delete_temp_keys()
%Jido.Agent.StateOp.DeleteKeys{keys: [:temp, :cache, :ephemeral]}
@spec execute_action_instruction(Jido.Agent.t(), Jido.Instruction.t(), strategy_ctx()) :: {Jido.Agent.t(), [struct()]}
Executes a non-strategy Jido.Action instruction using direct strategy semantics.
This is used as a fallback path in strategy adapters so plugin-routed action modules can run even when the strategy does not have a dedicated command atom.
@spec maybe_execute_action_instruction( Jido.Agent.t(), Jido.Instruction.t(), strategy_ctx() ) :: {Jido.Agent.t(), [struct()]} | :noop
Executes an instruction if its action is a loadable module implementing run/2.
Returns :noop when the action is not an executable module.
@spec prepend_conversation(map(), [map()]) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to prepend a message to the conversation.
Examples
iex> message = %{role: :user, content: "Hello"}
iex> current_conversation = [%{role: :assistant, content: "Hi"}]
iex> Helpers.prepend_conversation(message, current_conversation)
%Jido.Agent.StateOp.SetState{attrs: %{conversation: [%{role: :user, content: "Hello"}, %{role: :assistant, content: "Hi"}]}}
@spec remove_pending_tool(String.t()) :: Jido.Agent.StateOp.DeletePath.t()
Creates a StateOp to remove a specific pending tool by ID.
Examples
iex> Helpers.remove_pending_tool("call_1")
%Jido.Agent.StateOp.DeletePath{path: [:pending_tool_calls, "call_1"]}Note: This operation is meant for map-based pending_tool_calls. For list-based pending_tool_calls, use filter_pending_tools/1 instead.
@spec reset_strategy_state() :: Jido.Agent.StateOp.ReplaceState.t()
Creates a StateOp to reset the strategy state to initial values.
Examples
iex> result = Helpers.reset_strategy_state()
iex> result.state.status == :idle and result.state.iteration == 0
true
@spec set_call_id(String.t()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set the current LLM call ID.
Examples
iex> Helpers.set_call_id("call_123")
%Jido.Agent.StateOp.SetPath{path: [:current_llm_call_id], value: "call_123"}
@spec set_config_field(atom(), term()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set a specific config field.
Examples
iex> Helpers.set_config_field(:tools, [MyAction])
%Jido.Agent.StateOp.SetPath{path: [:config, :tools], value: [MyAction]}
@spec set_conversation([map()]) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to set the entire conversation.
Examples
iex> messages = [%{role: :user, content: "Hello"}, %{role: :assistant, content: "Hi"}]
iex> Helpers.set_conversation(messages)
%Jido.Agent.StateOp.SetState{attrs: %{conversation: messages}}
@spec set_final_answer(String.t()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set the final answer.
Examples
iex> Helpers.set_final_answer("42")
%Jido.Agent.StateOp.SetPath{path: [:final_answer], value: "42"}
@spec set_iteration(non_neg_integer()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to increment the iteration counter.
Note: This cannot directly read the current value, so it should be used with the current iteration value known from context.
Examples
iex> Helpers.set_iteration(5)
%Jido.Agent.StateOp.SetPath{path: [:iteration], value: 5}
@spec set_iteration_status(atom()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set the iteration status.
Examples
iex> Helpers.set_iteration_status(:awaiting_llm)
%Jido.Agent.StateOp.SetPath{path: [:status], value: :awaiting_llm}
@spec set_pending_tools([map()]) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to set pending tool calls.
Examples
iex> tools = [%{id: "call_1", name: "search", arguments: %{query: "test"}}]
iex> Helpers.set_pending_tools(tools)
%Jido.Agent.StateOp.SetState{attrs: %{pending_tool_calls: tools}}
@spec set_strategy_field(atom(), term()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set a specific field in the strategy state.
Examples
iex> Helpers.set_strategy_field(:status, :running)
%Jido.Agent.StateOp.SetPath{path: [:status], value: :running}
@spec set_streaming_text(String.t()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set the streaming text.
Examples
iex> Helpers.set_streaming_text("Hello")
%Jido.Agent.StateOp.SetPath{path: [:streaming_text], value: "Hello"}
@spec set_termination_reason(atom()) :: Jido.Agent.StateOp.SetPath.t()
Creates a StateOp to set the termination reason.
Examples
iex> Helpers.set_termination_reason(:final_answer)
%Jido.Agent.StateOp.SetPath{path: [:termination_reason], value: :final_answer}
@spec set_usage(map()) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to set the usage metadata.
Examples
iex> usage = %{input_tokens: 10, output_tokens: 20}
iex> Helpers.set_usage(usage)
%Jido.Agent.StateOp.SetState{attrs: %{usage: usage}}
@spec update_config(map()) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to update the config field in strategy state.
Examples
iex> config = %{tools: [], model: "test"}
iex> Helpers.update_config(config)
%Jido.Agent.StateOp.SetState{attrs: %{config: config}}
@spec update_config_fields(map()) :: [Jido.Agent.StateOp.SetPath.t()]
Creates StateOps to update multiple config fields at once.
Examples
iex> ops = Helpers.update_config_fields(%{tools: [], model: "test"})
iex> length(ops)
2
iex> hd(ops).path
[:config, :tools]
@spec update_strategy_state(map()) :: Jido.Agent.StateOp.SetState.t()
Creates a StateOp to update the strategy state.
Performs a deep merge of the given attributes into the strategy state.
Examples
iex> Helpers.update_strategy_state(%{status: :running, iteration: 1})
%Jido.Agent.StateOp.SetState{attrs: %{status: :running, iteration: 1}}
@spec update_tools_config([module()], %{required(String.t()) => module()}, [map()]) :: [ Jido.Agent.StateOp.SetPath.t() ]
Creates StateOps to update tools, actions_by_name, and reqllm_tools together.
This is a common pattern when registering/unregistering tools.
Examples
iex> tools = [SomeAction]
iex> actions_by_name = %{"action" => SomeAction}
iex> reqllm_tools = [%{name: "action"}]
iex> ops = Helpers.update_tools_config(tools, actions_by_name, reqllm_tools)
iex> length(ops)
3
iex> hd(ops).path
[:config, :tools]