Class: LLM::Agent::Registry Private

Inherits:
Object
  • Object
show all
Defined in:
lib/llm/agent/registry.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

LLM::Agent::Registry holds the agents that are running a turn in this process, so that a cancel can find one.

Delivery is not the problem it solves. LLM::Agent#interrupt! can be called from any thread, and LLM::Agent::Interrupt decides what receives the raise - but a canceller has to hold the agent, and in an application the agent is built inside the job that runs the turn and stays a local variable for as long as the turn lasts. A cancel button has nothing to reach.

So a turn registers itself for as long as it runs, and a canceller names it by the agent, or by the id it already has: the record's id when the agent was built around one, the agent's own otherwise.

What it does not promise

It is one process, and it holds the agents that process is running. A cancel that lands elsewhere - a second worker, a deploy that leaves two up for a minute - finds nothing, and false must not be read as "the turn is over". An application that needs a guarantee keeps one of its own; this is the fast path.

Instance Method Summary collapse

Constructor Details

#initialize ⇒ LLM::Agent::Registry

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



31
32
33
34
# File 'lib/llm/agent/registry.rb', line 31

def initialize
  @agents = {}
  @mutex  = Mutex.new
end

Instance Method Details

#enter(agent) ⇒ LLM::Agent

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Records that an agent is running a turn.

Strongly, and that is the point: an entry has to reach an agent that is blocked inside talk, so a weak reference would let a turn that is running be collected. The lifetime is the caller's ensure.

Parameters:

Returns:



45
46
47
48
# File 'lib/llm/agent/registry.rb', line 45

def enter(agent)
  @mutex.synchronize { @agents[key(agent)] = agent }
  agent
end

#exit(agent)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Records that an agent's turn is over.

Removed only if it is still the agent that registered. Two turns under one identity - a second attempt alongside one that is finishing - are not the same turn, and the one that finishes first must not take the other one's registration with it.

Parameters:



59
60
61
62
63
64
# File 'lib/llm/agent/registry.rb', line 59

def exit(agent)
  @mutex.synchronize do
    id = key(agent)
    @agents.delete(id) if @agents[id].equal?(agent)
  end
end

#find(agent: nil, id: nil) ⇒ LLM::Agent?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The agent running a turn under this identity, or nil.

Named by the agent or by the id, and not by both: the two are the same question asked with different things in hand. An id is compared with ==, so a host may pass a string, a number, or whatever it holds that equals the id a turn registered under.

Looked up under the lock and answered outside it, because the interrupt that follows is not this class's to make: a caller holding the lock while raising into another thread's turn would be holding it against that turn's own exit.

Parameters:

  • agent (LLM::Agent, nil) (defaults to: nil)
  • id (String, Integer, nil) (defaults to: nil)

Returns:

Raises:

  • (ArgumentError) —

    When neither is given, or when both are



83
84
85
86
87
88
89
# File 'lib/llm/agent/registry.rb', line 83

def find(agent: nil, id: nil)
  if (agent.nil? and id.nil?) or (!agent.nil? and !id.nil?)
    raise ArgumentError, "provide an agent or an id, and not both"
  else
    @mutex.synchronize { @agents[agent ? key(agent) : id] }
  end
end