Class: Legion::CLI::Chat::Tools::TriggerDream

Inherits:
Tools::Base
  • Object
show all
Defined in:
lib/legion/cli/chat/tools/trigger_dream.rb

Constant Summary collapse

DEFAULT_PORT =
4567
DEFAULT_HOST =
'127.0.0.1'
DREAM_RUNNER =
'Legion::Extensions::Agentic::Imagination::Dream::Runners::DreamCycle'
DREAM_FUNCTION =
'execute_dream_cycle'

Class Method Summary collapse

Methods inherited from Tools::Base

deferred, deferred?, description, error_response, extension, handle_exception, input_schema, log, mcp_category, mcp_tier, runner, sticky, tags, text_response, tool_name, trigger_words

Class Method Details

.api_portObject



109
110
111
112
113
114
115
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 109

def self.api_port
  return DEFAULT_PORT unless defined?(Legion::Settings)

  Legion::Settings[:api]&.dig(:port) || DEFAULT_PORT
rescue StandardError
  DEFAULT_PORT
end

.api_post(path, body) ⇒ Object



98
99
100
101
102
103
104
105
106
107
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 98

def self.api_post(path, body)
  uri = URI("http://#{DEFAULT_HOST}:#{api_port}#{path}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = 5
  http.read_timeout = 10
  request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
  request.body = body
  response = http.request(request)
  ::JSON.parse(response.body, symbolize_names: true)
end

.call(action: 'trigger') ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 35

def self.call(action: 'trigger')
  case action.to_s
  when 'journal' then handle_journal
  else handle_trigger
  end
rescue Errno::ECONNREFUSED
  'Legion daemon not running (cannot reach API).'
rescue StandardError => e
  Legion::Logging.warn("TriggerDream#execute failed: #{e.message}") if defined?(Legion::Logging)
  "Error: #{e.message}"
end

.dream_log_dirsObject



74
75
76
77
78
79
80
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 74

def self.dream_log_dirs
  dirs = []
  dirs << File.expand_path('logs/dreams', gem_path) if gem_path
  dirs << File.expand_path('.legion/dreams', Dir.pwd)
  dirs << File.expand_path('~/.legionio/dreams')
  dirs.select { |d| Dir.exist?(d) }
end

.find_latest_journalObject



69
70
71
72
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 69

def self.find_latest_journal
  paths = dream_log_dirs.flat_map { |dir| Dir.glob(File.join(dir, 'dream-*.md')) }
  paths.last
end

.format_task_id(response) ⇒ Object



89
90
91
92
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 89

def self.format_task_id(response)
  task_id = response.dig(:data, :task_id) || response.dig(:data, :id)
  task_id ? "Task ID: #{task_id}" : ''
end

.gem_pathObject



82
83
84
85
86
87
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 82

def self.gem_path
  spec = Gem::Specification.find_by_name('lex-agentic-imagination')
  spec&.gem_dir
rescue Gem::MissingSpecError
  nil
end

.handle_journalObject



61
62
63
64
65
66
67
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 61

def self.handle_journal
  journal_path = find_latest_journal
  return 'No dream journal entries found.' unless journal_path

  content = File.read(journal_path, encoding: 'utf-8')
  truncate(content, 2000)
end

.handle_triggerObject



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 47

def self.handle_trigger
  body = ::JSON.generate({
                           runner_class:  DREAM_RUNNER,
                           function:      DREAM_FUNCTION,
                           async:         true,
                           check_subtask: false,
                           generate_task: false
                         })
  response = api_post('/api/tasks', body)
  return "Dream cycle triggered. #{format_task_id(response)}" if response[:data]

  "Dream trigger failed: #{response.dig(:error, :message) || 'unknown error'}"
end

.truncate(text, max) ⇒ Object



94
95
96
# File 'lib/legion/cli/chat/tools/trigger_dream.rb', line 94

def self.truncate(text, max)
  text.length > max ? "#{text[0..(max - 4)]}..." : text
end