Class: Insika::Hooks

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/hooks.rb

Overview

Hooks ALTER the input/output of the ONE stage they wrap: Middleware modifies, Hooks alter, Events observe. They don't create their own flow nor skip stages. Synchronous and without rescue — the error->state mapping belongs to the Executor.

Constant Summary collapse

PAIRS =
%i[task prompt agent tool].freeze

Instance Method Summary collapse

Constructor Details

#initializeHooks

Returns a new instance of Hooks.



10
11
12
13
# File 'lib/insika/hooks.rb', line 10

def initialize
  @before = Hash.new { |h, k| h[k] = [] }
  @after = Hash.new { |h, k| h[k] = [] }
end

Instance Method Details

#around(pair, subject) ⇒ Object

befores in registration order (may ALTER the subject by returning the new one), yield(subject), afters in REVERSE order (may alter the result). With no registrations -> degenerates into yield(subject) (no-op). A hook that doesn't alter returns what it received; returning nil IS altering to nil (no special case).



28
29
30
# File 'lib/insika/hooks.rb', line 28

def around(pair, subject)
  run_after(pair, yield(run_before(pair, subject)))
end

#register(pair, before: nil, after: nil) ⇒ Object

callables; multiple per pair. Registration order is significant.

Raises:

  • (ArgumentError)


16
17
18
19
20
21
22
# File 'lib/insika/hooks.rb', line 16

def register(pair, before: nil, after: nil)
  raise ArgumentError, "unknown hook pair: #{pair.inspect}" unless PAIRS.include?(pair)

  @before[pair] << before if before
  @after[pair] << after if after
  nil
end

#run_after(pair, result) ⇒ Object

Raises:

  • (ArgumentError)


42
43
44
45
46
# File 'lib/insika/hooks.rb', line 42

def run_after(pair, result)
  raise ArgumentError, "unknown hook pair: #{pair.inspect}" unless PAIRS.include?(pair)

  @after[pair].reverse.reduce(result) { |res, hook| hook.call(res) }
end

#run_before(pair, subject) ⇒ Object

Public halves of around. Needed for the :tool pair, whose stage "body" is RubyLLM's inner loop — there is no block to wrap; the halves are called from the before_tool_call/ after_tool_result callbacks separately.

Raises:

  • (ArgumentError)


36
37
38
39
40
# File 'lib/insika/hooks.rb', line 36

def run_before(pair, subject)
  raise ArgumentError, "unknown hook pair: #{pair.inspect}" unless PAIRS.include?(pair)

  @before[pair].reduce(subject) { |subj, hook| hook.call(subj) }
end