# =============================================================================== # Copyright (c) 2025, Noizu Labs, Inc. # =============================================================================== defmodule GenAI.Session.State do @moduledoc """ Represent status/state such as node state, sessions, message thread, etc. """ require GenAI.Records.Directive import GenAI.Records.Directive # require GenAI.Records.Session defstruct directives: [], directive_position: 0, thread: [], thread_messages: %{}, stack: %{}, data_generators: %{}, options: %{}, settings: %{}, model_settings: %{}, provider_settings: %{}, safety_settings: %{}, model: nil, tools: %{}, monitors: %{}, artifacts: %{}, vsn: 1.0 @type t :: %__MODULE__{ directives: list(), directive_position: non_neg_integer(), thread: list(), thread_messages: map(), stack: map(), data_generators: map(), options: map(), settings: map(), model_settings: map(), provider_settings: map(), safety_settings: map(), model: term(), tools: map(), monitors: map(), artifacts: map(), vsn: float() } # =========================================================================== # entry selectors # =========================================================================== def entry_path(message_entry(msg: entry)), do: [Access.key(:thread_messages), entry] def entry_path(stack_entry(element: entry)), do: [Access.key(:stack), entry] def entry_path(data_generator_entry(generator: entry)), do: [Access.key(:data_generators), entry] def entry_path(option_entry(option: entry)), do: [Access.key(:options), entry] def entry_path(setting_entry(setting: entry)), do: [Access.key(:settings), entry] def entry_path(model_setting_entry(model: model, setting: entry)) do with {:ok, name} <- GenAI.ModelProtocol.name(model), {:ok, provider} <- GenAI.ModelProtocol.provider(model) do [Access.key(:model_settings), Access.key({name, provider}, %{}), entry] end # do: [Access.key(:model_settings), Access.key(model, %{}), entry] end def entry_path(provider_setting_entry(provider: provider, setting: entry)), do: [Access.key(:provider_settings), Access.key(provider, %{}), entry] def entry_path(safety_setting_entry(category: entry)), do: [Access.key(:safety_settings), entry] def entry_path(model_entry()), do: [Access.key(:model)] def entry_path(tool_entry(tool: entry)), do: [Access.key(:tools), entry] def entry_path(monitor_entry(monitor: entry)), do: [Access.key(:monitors), entry] # =========================================================================== # # =========================================================================== # defp memoize(entry, value, memo) # defp memoize(entry, value, memo) do # Map.put(memo, entry, value) # end # ----------------------- # new/1 # ----------------------- def new(options \\ nil) def new(_) do %__MODULE__{} end # ----------------------- # initialize/4 # ----------------------- def initialize(state, runtime, context, options \\ nil) def initialize(state, _runtime, _context, _options) do {:ok, state} end # ----------------------- # monitor/4 # ----------------------- def monitor(state, runtime, context, options \\ nil) def monitor(state, runtime, _, _) do {:ok, {state, runtime}} end # # # ------------------------ # # reference_expired?/5 # # ------------------------ # @spec reference_expired?( # R.Session.entry_reference(), # __MODULE__.t(), # R.Session.context(), # R.Session.options() # ) :: {boolean, {R.Session.entry_reference(), R.Session.state(), Map.t()}} # @spec reference_expired?( # R.Session.entry_reference(), # __MODULE__.t(), # R.Session.context(), # R.Session.options(), # Map.t() # ) :: {boolean, {R.Session.entry_reference(), R.Session.state(), Map.t()}} # def reference_expired?(reference, this, context, options, memo \\ %{}) # # def reference_expired?( # reference = R.Session.entry_reference(expired?: true), # this, # _, # _, # memo # ) do # {true, {reference, this, memo}} # end # # def reference_expired?( # reference = R.Session.entry_reference(entry: entry, finger_print: finger_print), # this, # context, # options, # memo # ) do # reference_key = {entry, finger_print} # # if x = memo[reference_key] do # {x, {R.Session.entry_reference(reference, expired?: x), this, memo}} # else # # todo return nil for unchanged values. # with %SettingEntry{} = entry <- get_in(this, apply_setting_path(reference)), # {expired?, {updated_entry, updated_state, updated_memo}} <- # SettingEntry.reference_expired?(entry, this, context, options, memo) do # updated_state = put_in(updated_state, apply_setting_path(entry), updated_entry) # updated_memo = memoize(reference_key, expired?, updated_memo) # # updated_reference = # if expired?, # do: R.Session.entry_reference(reference, expired?: expired?), # else: reference # # {expired?, {updated_reference, updated_state, updated_memo}} # else # _ -> # updated_memo = memoize(reference_key, true, memo) # {true, {R.Session.entry_reference(reference, expired?: true), this, updated_memo}} # end # end # end # # end