llama_bot_rails 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -0
- data/app/channels/llama_bot_rails/chat_channel.rb +10 -6
- data/app/controllers/llama_bot_rails/agent_controller.rb +35 -31
- data/app/views/llama_bot_rails/agent/chat_ws.html.erb +1 -1
- data/bin/bundle +29 -0
- data/bin/bundle.lock +0 -0
- data/bin/bundler +29 -0
- data/bin/bundler.lock +0 -0
- data/bin/byebug +29 -0
- data/bin/coderay +29 -0
- data/bin/erb +29 -0
- data/bin/faker +29 -0
- data/bin/htmldiff +29 -0
- data/bin/irb +29 -0
- data/bin/ldiff +29 -0
- data/bin/nokogiri +29 -0
- data/bin/pry +29 -0
- data/bin/puma +29 -0
- data/bin/pumactl +29 -0
- data/bin/racc +29 -0
- data/bin/rackup +29 -0
- data/bin/rake +29 -0
- data/bin/rdoc +29 -0
- data/bin/ri +29 -0
- data/bin/rspec +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/sprockets +29 -0
- data/bin/thor +29 -0
- data/lib/generators/llama_bot_rails/install/install_generator.rb +68 -0
- data/lib/llama_bot_rails/agent_auth.rb +155 -0
- data/lib/llama_bot_rails/controller_extensions.rb +40 -0
- data/lib/llama_bot_rails/engine.rb +8 -2
- data/lib/llama_bot_rails/railtie.rb +6 -0
- data/lib/llama_bot_rails/version.rb +1 -1
- data/lib/llama_bot_rails.rb +62 -20
- metadata +29 -4
- data/bin/rails +0 -26
- data/bin/rubocop +0 -8
data/bin/rdoc
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'rdoc' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('rdoc', 'rdoc', version)
|
26
|
+
else
|
27
|
+
gem "rdoc", version
|
28
|
+
load Gem.bin_path("rdoc", "rdoc", version)
|
29
|
+
end
|
data/bin/ri
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'rdoc' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('rdoc', 'ri', version)
|
26
|
+
else
|
27
|
+
gem "rdoc", version
|
28
|
+
load Gem.bin_path("rdoc", "ri", version)
|
29
|
+
end
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'rspec-core' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('rspec-core', 'rspec', version)
|
26
|
+
else
|
27
|
+
gem "rspec-core", version
|
28
|
+
load Gem.bin_path("rspec-core", "rspec", version)
|
29
|
+
end
|
data/bin/ruby-parse
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'parser' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('parser', 'ruby-parse', version)
|
26
|
+
else
|
27
|
+
gem "parser", version
|
28
|
+
load Gem.bin_path("parser", "ruby-parse", version)
|
29
|
+
end
|
data/bin/ruby-rewrite
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'parser' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('parser', 'ruby-rewrite', version)
|
26
|
+
else
|
27
|
+
gem "parser", version
|
28
|
+
load Gem.bin_path("parser", "ruby-rewrite", version)
|
29
|
+
end
|
data/bin/sprockets
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'sprockets' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('sprockets', 'sprockets', version)
|
26
|
+
else
|
27
|
+
gem "sprockets", version
|
28
|
+
load Gem.bin_path("sprockets", "sprockets", version)
|
29
|
+
end
|
data/bin/thor
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'thor' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
Gem.use_gemdeps
|
12
|
+
|
13
|
+
version = ">= 0.a"
|
14
|
+
|
15
|
+
str = ARGV.first
|
16
|
+
if str
|
17
|
+
str = str.b[/\A_(.*)_\z/, 1]
|
18
|
+
if str and Gem::Version.correct?(str)
|
19
|
+
version = str
|
20
|
+
ARGV.shift
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if Gem.respond_to?(:activate_bin_path)
|
25
|
+
load Gem.activate_bin_path('thor', 'thor', version)
|
26
|
+
else
|
27
|
+
gem "thor", version
|
28
|
+
load Gem.bin_path("thor", "thor", version)
|
29
|
+
end
|
@@ -63,6 +63,74 @@ module LlamaBotRails
|
|
63
63
|
# Uncomment this line to use the builder in app/llama_bot/
|
64
64
|
#
|
65
65
|
# config.llama_bot_rails.state_builder_class = "#{app_name}::AgentStateBuilder"
|
66
|
+
|
67
|
+
# ------------------------------------------------------------------------
|
68
|
+
# Custom User Resolver
|
69
|
+
# ------------------------------------------------------------------------
|
70
|
+
# The gem uses `warden.user` by default.
|
71
|
+
# Uncomment this line to use a custom user resolver in app/llama_bot/
|
72
|
+
# Example: if you don't use Devise, uncomment and tweak:
|
73
|
+
#
|
74
|
+
# LlamaBotRails.user_resolver = ->(user_id) do
|
75
|
+
# # Try to find a User model, fallback to nil if not found
|
76
|
+
# if defined?(Devise)
|
77
|
+
# default_scope = Devise.default_scope # e.g., :user
|
78
|
+
# user_class = Devise.mappings[default_scope].to
|
79
|
+
# user_class.find_by(id: user_id)
|
80
|
+
# else
|
81
|
+
# Rails.logger.warn("[[LlamaBot]] Implement a user_resolver! in your app to resolve the user from the user_id.")
|
82
|
+
# nil
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
|
86
|
+
# ------------------------------------------------------------------------
|
87
|
+
# Custom Current User Resolver
|
88
|
+
# ------------------------------------------------------------------------
|
89
|
+
# Default (Devise / Warden); returns nil if Devise absent
|
90
|
+
#
|
91
|
+
# LlamaBotRails.current_user_resolver = ->(env) do
|
92
|
+
# # Try to find a User model, fallback to nil if not found
|
93
|
+
# if defined?(Devise)
|
94
|
+
# env['warden']&.user
|
95
|
+
# else
|
96
|
+
# Rails.logger.warn("[[LlamaBot]] Implement a current_user_resolver! in your app to resolve the current user from the environment.")
|
97
|
+
# nil
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
|
101
|
+
# ------------------------------------------------------------------------
|
102
|
+
# Custom Sign-in Method
|
103
|
+
# ------------------------------------------------------------------------
|
104
|
+
# Lambda that receives Rack env and user_id, and sets the user in the warden session
|
105
|
+
# Default sign-in method is configured for Devise with Warden.
|
106
|
+
#
|
107
|
+
# LlamaBotRails.sign_in_method = ->(env, user) do
|
108
|
+
# env['warden']&.set_user(user)
|
109
|
+
# end
|
110
|
+
|
111
|
+
# ------------------------------------------------------------------------
|
112
|
+
# Alternative Examples for Non-Devise Apps
|
113
|
+
# ------------------------------------------------------------------------
|
114
|
+
# Example: if you don't use Devise, uncomment and tweak:
|
115
|
+
#
|
116
|
+
# LlamaBotRails.user_resolver = ->(user_id) do
|
117
|
+
# # Rack session example
|
118
|
+
# if user_id
|
119
|
+
# User.find_by(id: user_id)
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# LlamaBotRails.current_user_resolver = ->(env) do
|
124
|
+
# # Rack session example
|
125
|
+
# if id = env['rack.session'][:user_id]
|
126
|
+
# User.find_by(id: id)
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# LlamaBotRails.sign_in_method = ->(env, user) do
|
131
|
+
# # Set user in rack session
|
132
|
+
# env['rack.session'][:user_id] = user&.id
|
133
|
+
# end
|
66
134
|
end
|
67
135
|
RUBY
|
68
136
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module LlamaBotRails
|
2
|
+
module AgentAuth
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
AUTH_SCHEME = "LlamaBot"
|
5
|
+
|
6
|
+
included do
|
7
|
+
# Add before_action filter to automatically check agent authentication for LlamaBot requests
|
8
|
+
before_action :check_agent_authentication, if: :should_check_agent_auth?
|
9
|
+
|
10
|
+
# ------------------------------------------------------------------
|
11
|
+
# 1) For every Devise scope, alias authenticate_<scope>! so it now
|
12
|
+
# accepts *either* a logged-in browser session OR a valid agent
|
13
|
+
# token. Existing before/skip filters keep working.
|
14
|
+
# ------------------------------------------------------------------
|
15
|
+
if defined?(Devise)
|
16
|
+
Devise.mappings.keys.each do |scope|
|
17
|
+
scope_filter = :"authenticate_#{scope}!"
|
18
|
+
|
19
|
+
# Next line is a no-op if the method wasn’t already defined.
|
20
|
+
alias_method scope_filter, :authenticate_user_or_agent! \
|
21
|
+
if method_defined?(scope_filter)
|
22
|
+
|
23
|
+
# Emit a gentle nudge during development
|
24
|
+
define_method(scope_filter) do |*args|
|
25
|
+
Rails.logger.warn(
|
26
|
+
"#{scope_filter} is now handled by LlamaBotRails::AgentAuth "\
|
27
|
+
"and will be removed in a future version. "\
|
28
|
+
"Use authenticate_user_or_agent! instead."
|
29
|
+
)
|
30
|
+
authenticate_user_or_agent!(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ------------------------------------------------------------------
|
36
|
+
# 2) If Devise isn’t loaded at all, fall back to one alias so apps
|
37
|
+
# that had authenticate_user! manually defined don’t break.
|
38
|
+
# ------------------------------------------------------------------
|
39
|
+
unless defined?(Devise)
|
40
|
+
# Store the original method if it exists
|
41
|
+
original_authenticate_user = if method_defined?(:authenticate_user!)
|
42
|
+
instance_method(:authenticate_user!)
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# Define the new method that calls authenticate_user_or_agent!
|
48
|
+
define_method(:authenticate_user!) do |*args|
|
49
|
+
authenticate_user_or_agent!(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# --------------------------------------------------------------------
|
55
|
+
# Public helper: true if the request carries a *valid* agent token
|
56
|
+
# --------------------------------------------------------------------
|
57
|
+
def should_check_agent_auth?
|
58
|
+
# Skip agent authentication entirely if a Devise user is already signed in
|
59
|
+
return false if devise_user_signed_in?
|
60
|
+
|
61
|
+
# Only check for LlamaBot requests if no Devise user is signed in
|
62
|
+
llama_bot_request?
|
63
|
+
end
|
64
|
+
|
65
|
+
def llama_bot_request?
|
66
|
+
return false unless request&.headers
|
67
|
+
scheme, token = request.headers["Authorization"]&.split(" ", 2)
|
68
|
+
Rails.logger.debug("[LlamaBot] auth header = #{scheme.inspect} #{token&.slice(0,8)}…")
|
69
|
+
return false unless scheme == AUTH_SCHEME && token.present?
|
70
|
+
|
71
|
+
Rails.application.message_verifier(:llamabot_ws).verify(token)
|
72
|
+
true
|
73
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
74
|
+
false
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# --------------------------------------------------------------------
|
80
|
+
# Automatic check for LlamaBot requests - called by before_action filter
|
81
|
+
# --------------------------------------------------------------------
|
82
|
+
def check_agent_authentication
|
83
|
+
# Check if this controller has LlamaBot-aware actions
|
84
|
+
has_permitted_actions = self.class.respond_to?(:llama_bot_permitted_actions)
|
85
|
+
|
86
|
+
# Skip if controller doesn't use llama_bot_allow at all
|
87
|
+
return unless has_permitted_actions
|
88
|
+
|
89
|
+
is_llama_request = llama_bot_request?
|
90
|
+
action_is_whitelisted = self.class.llama_bot_permitted_actions.include?(action_name)
|
91
|
+
|
92
|
+
if is_llama_request
|
93
|
+
# If it's a LlamaBot request, only allow whitelisted actions
|
94
|
+
unless action_is_whitelisted
|
95
|
+
Rails.logger.warn("[LlamaBot] Action '#{action_name}' isn't white-listed for LlamaBot. To fix this, add `llama_bot_allow :#{action_name}` in your controller.")
|
96
|
+
render json: { error: "Action '#{action_name}' isn't white-listed for LlamaBot. To fix this, add `llama_bot_allow :#{action_name}` in your controller." }, status: :forbidden
|
97
|
+
return
|
98
|
+
end
|
99
|
+
Rails.logger.debug("[[LlamaBot Debug]] Valid LlamaBot request for action '#{action_name}'")
|
100
|
+
elsif action_is_whitelisted
|
101
|
+
# If action requires LlamaBot auth but request isn't a LlamaBot request, reject it
|
102
|
+
Rails.logger.warn("[LlamaBot] Action '#{action_name}' requires LlamaBot authentication, but request is not a valid LlamaBot request.")
|
103
|
+
render json: { error: "Action '#{action_name}' requires LlamaBot authentication" }, status: :forbidden
|
104
|
+
return
|
105
|
+
end
|
106
|
+
|
107
|
+
# All other cases: non-LlamaBot requests to non-whitelisted actions are allowed
|
108
|
+
end
|
109
|
+
|
110
|
+
# --------------------------------------------------------------------
|
111
|
+
# Unified guard — browser OR agent
|
112
|
+
# --------------------------------------------------------------------
|
113
|
+
def devise_user_signed_in?
|
114
|
+
return false unless defined?(Devise)
|
115
|
+
return false unless request&.env
|
116
|
+
request.env["warden"]&.authenticated?
|
117
|
+
end
|
118
|
+
|
119
|
+
def authenticate_user_or_agent!(*)
|
120
|
+
return if devise_user_signed_in? # any logged-in Devise scope
|
121
|
+
|
122
|
+
# 2) LlamaBot token present AND action allowed?
|
123
|
+
if llama_bot_request?
|
124
|
+
scheme, token = request.headers["Authorization"]&.split(" ", 2)
|
125
|
+
data = Rails.application.message_verifier(:llamabot_ws).verify(token)
|
126
|
+
|
127
|
+
allowed = self.class.respond_to?(:llama_bot_permitted_actions) &&
|
128
|
+
self.class.llama_bot_permitted_actions.include?(action_name)
|
129
|
+
|
130
|
+
if allowed
|
131
|
+
|
132
|
+
user_object = LlamaBotRails.user_resolver.call(data[:user_id])
|
133
|
+
unless LlamaBotRails.sign_in_method.call(request.env, user_object)
|
134
|
+
head :unauthorized
|
135
|
+
end
|
136
|
+
|
137
|
+
return # ✅ token + allow-listed action + user found and set properly for rack environment
|
138
|
+
else
|
139
|
+
# ❌ auth token is valid, but the attempted controller action is not added to the whitelist.
|
140
|
+
Rails.logger.warn("[LlamaBot] Action '#{action_name}' isn't white-listed for LlamaBot. To fix this, include LlamaBotRails::ControllerExtensions and add `llama_bot_allow :method` in your controller.")
|
141
|
+
render json: { error: "Action '#{action_name}' isn't white-listed for LlamaBot. To fix this, include LlamaBotRails::ControllerExtensions and add `llama_bot_allow :method` in your controller." }, status: :forbidden
|
142
|
+
return false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Neither path worked — fall back to Devise's normal behaviour and let Devise handle 401
|
147
|
+
if defined?(Devise) && request&.env
|
148
|
+
request.env["warden"].authenticate! # 401 or redirect
|
149
|
+
else
|
150
|
+
head :unauthorized
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module LlamaBotRails
|
3
|
+
module ControllerExtensions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# NEW: per-controller class attribute that stores the allow-list
|
8
|
+
class_attribute :llama_bot_permitted_actions,
|
9
|
+
instance_writer: false,
|
10
|
+
default: []
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
# Usage: llama_bot_allow :update, :preview
|
15
|
+
def llama_bot_allow(*actions)
|
16
|
+
# normalise to strings so `include?(action_name)` works
|
17
|
+
acts = actions.map(&:to_s)
|
18
|
+
|
19
|
+
# Check if this specific class has had llama_bot_allow called directly on it
|
20
|
+
if instance_variable_defined?(:@_llama_bot_allow_called)
|
21
|
+
# This class has been configured before, accumulate with existing
|
22
|
+
current_actions = llama_bot_permitted_actions || []
|
23
|
+
else
|
24
|
+
# First time configuring this class, start fresh (ignore inherited values)
|
25
|
+
current_actions = []
|
26
|
+
@_llama_bot_allow_called = true
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create a new array to ensure inheritance doesn't share state
|
30
|
+
self.llama_bot_permitted_actions = (current_actions + acts).uniq
|
31
|
+
|
32
|
+
# (optional) keep your global registry if you still need it
|
33
|
+
if defined?(LlamaBotRails.allowed_routes)
|
34
|
+
acts.each { |a| LlamaBotRails.allowed_routes << "#{controller_path}##{a}" }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -11,8 +11,9 @@ module LlamaBotRails
|
|
11
11
|
end
|
12
12
|
|
13
13
|
config.llama_bot_rails = ActiveSupport::OrderedOptions.new
|
14
|
-
|
15
|
-
config.llama_bot_rails.
|
14
|
+
|
15
|
+
config.llama_bot_rails.websocket_url = 'ws://llamabot-backend:8000/ws'
|
16
|
+
config.llama_bot_rails.llamabot_api_url ="http://llamabot-backend:8000"
|
16
17
|
config.llama_bot_rails.enable_console_tool = true
|
17
18
|
|
18
19
|
initializer "llama_bot_rails.assets.precompile" do |app|
|
@@ -22,5 +23,10 @@ module LlamaBotRails
|
|
22
23
|
initializer "llama_bot_rails.defaults" do |app|
|
23
24
|
app.config.llama_bot_rails.state_builder_class ||= "LlamaBotRails::AgentStateBuilder"
|
24
25
|
end
|
26
|
+
|
27
|
+
initializer "llama_bot_rails.message_verifier" do |app|
|
28
|
+
# Ensure the message verifier is available
|
29
|
+
Rails.application.message_verifier(:llamabot_ws)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module LlamaBotRails
|
2
2
|
class Railtie < ::Rails::Railtie
|
3
|
+
initializer "llama_bot.include_controller_extensions" do
|
4
|
+
ActiveSupport.on_load(:action_controller) do
|
5
|
+
include LlamaBotRails::ControllerExtensions
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
config.before_configuration do |app|
|
4
10
|
llama_bot_path = Rails.root.join("app", "llama_bot")
|
5
11
|
|
data/lib/llama_bot_rails.rb
CHANGED
@@ -1,35 +1,77 @@
|
|
1
|
+
require "set" # ← you call Set.new
|
1
2
|
require "llama_bot_rails/version"
|
2
3
|
require "llama_bot_rails/engine"
|
3
|
-
|
4
|
-
# require "llama_bot_rails/railtie" # We don't need this, as we're loading the LlamaBot path directly in the engine.
|
5
4
|
require "llama_bot_rails/llama_bot"
|
6
5
|
require "llama_bot_rails/agent_state_builder"
|
6
|
+
require "llama_bot_rails/controller_extensions"
|
7
|
+
require "llama_bot_rails/agent_auth"
|
7
8
|
|
8
9
|
module LlamaBotRails
|
10
|
+
# ------------------------------------------------------------------
|
11
|
+
# Public configuration
|
12
|
+
# ------------------------------------------------------------------
|
13
|
+
|
14
|
+
# Allow-list of routes the agent may hit
|
15
|
+
mattr_accessor :allowed_routes, default: Set.new
|
16
|
+
|
17
|
+
# Lambda that receives Rack env and returns a user-like object
|
9
18
|
class << self
|
10
|
-
|
11
|
-
|
12
|
-
end
|
19
|
+
attr_accessor :user_resolver
|
20
|
+
attr_accessor :current_user_resolver
|
13
21
|
|
14
|
-
|
15
|
-
|
22
|
+
attr_accessor :sign_in_method
|
23
|
+
end
|
24
|
+
|
25
|
+
# Default (Devise / Warden); returns nil if Devise absent
|
26
|
+
self.user_resolver = ->(user_id) do
|
27
|
+
# Try to find a User model, fallback to nil if not found
|
28
|
+
# byebug
|
29
|
+
if defined?(Devise)
|
30
|
+
default_scope = Devise.default_scope # e.g., :user
|
31
|
+
user_class = Devise.mappings[default_scope].to
|
32
|
+
user_class.find_by(id: user_id)
|
33
|
+
else
|
34
|
+
Rails.logger.warn("[[LlamaBot]] Implement a user_resolver! in your app to resolve the user from the user_id.")
|
35
|
+
nil
|
16
36
|
end
|
37
|
+
end
|
17
38
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
39
|
+
# Default (Devise / Warden); returns nil if Devise absent
|
40
|
+
self.current_user_resolver = ->(env) do
|
41
|
+
# Try to find a User model, fallback to nil if not found
|
42
|
+
if defined?(Devise)
|
43
|
+
env['warden']&.user
|
44
|
+
else
|
45
|
+
Rails.logger.warn("[[LlamaBot]] Implement a current_user_resolver! in your app to resolve the current user from the environment.")
|
46
|
+
nil
|
24
47
|
end
|
48
|
+
end
|
25
49
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
50
|
+
# Lambda that receives Rack env and user_id, and sets the user in the warden session
|
51
|
+
# Default sign-in method is configured for Devise with Warden.
|
52
|
+
self.sign_in_method = ->(env, user) do
|
53
|
+
env['warden']&.set_user(user)
|
54
|
+
end
|
30
55
|
|
31
|
-
|
32
|
-
|
33
|
-
|
56
|
+
# Convenience helper for host-app initializers
|
57
|
+
def self.config = Rails.application.config.llama_bot_rails
|
58
|
+
|
59
|
+
# ------------------------------------------------------------------
|
60
|
+
# Prompt helpers
|
61
|
+
# ------------------------------------------------------------------
|
62
|
+
def self.agent_prompt_path = Rails.root.join("app", "llama_bot", "prompts", "agent_prompt.txt")
|
63
|
+
|
64
|
+
def self.agent_prompt_text
|
65
|
+
File.exist?(agent_prompt_path) ? File.read(agent_prompt_path) : "You are LlamaBot, a helpful assistant."
|
34
66
|
end
|
67
|
+
|
68
|
+
def self.add_instruction_to_agent_prompt!(str)
|
69
|
+
FileUtils.mkdir_p(agent_prompt_path.dirname)
|
70
|
+
File.write(agent_prompt_path, "\n#{str}", mode: "a")
|
71
|
+
end
|
72
|
+
|
73
|
+
# ------------------------------------------------------------------
|
74
|
+
# Bridge to backend service
|
75
|
+
# ------------------------------------------------------------------
|
76
|
+
def self.send_agent_message(params) = LlamaBot.send_agent_message(params)
|
35
77
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: llama_bot_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kody Kendall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -119,15 +119,40 @@ files:
|
|
119
119
|
- app/views/layouts/llama_bot_rails/application.html.erb
|
120
120
|
- app/views/llama_bot_rails/agent/chat.html.erb
|
121
121
|
- app/views/llama_bot_rails/agent/chat_ws.html.erb
|
122
|
-
- bin/
|
123
|
-
- bin/
|
122
|
+
- bin/bundle
|
123
|
+
- bin/bundle.lock
|
124
|
+
- bin/bundler
|
125
|
+
- bin/bundler.lock
|
126
|
+
- bin/byebug
|
127
|
+
- bin/coderay
|
128
|
+
- bin/erb
|
129
|
+
- bin/faker
|
130
|
+
- bin/htmldiff
|
131
|
+
- bin/irb
|
132
|
+
- bin/ldiff
|
133
|
+
- bin/nokogiri
|
134
|
+
- bin/pry
|
135
|
+
- bin/puma
|
136
|
+
- bin/pumactl
|
137
|
+
- bin/racc
|
138
|
+
- bin/rackup
|
139
|
+
- bin/rake
|
140
|
+
- bin/rdoc
|
141
|
+
- bin/ri
|
142
|
+
- bin/rspec
|
143
|
+
- bin/ruby-parse
|
144
|
+
- bin/ruby-rewrite
|
145
|
+
- bin/sprockets
|
146
|
+
- bin/thor
|
124
147
|
- config/initializers/llama_bot_rails.rb
|
125
148
|
- config/routes.rb
|
126
149
|
- lib/generators/llama_bot_rails/install/install_generator.rb
|
127
150
|
- lib/generators/llama_bot_rails/install/templates/agent_prompt.txt
|
128
151
|
- lib/generators/llama_bot_rails/install/templates/agent_state_builder.rb.erb
|
129
152
|
- lib/llama_bot_rails.rb
|
153
|
+
- lib/llama_bot_rails/agent_auth.rb
|
130
154
|
- lib/llama_bot_rails/agent_state_builder.rb
|
155
|
+
- lib/llama_bot_rails/controller_extensions.rb
|
131
156
|
- lib/llama_bot_rails/engine.rb
|
132
157
|
- lib/llama_bot_rails/llama_bot.rb
|
133
158
|
- lib/llama_bot_rails/railtie.rb
|