Skip to content

Commit 1655d09

Browse files
Assistant generator creates a basic UI (#112)
* WIP: Adding rough views+controller to be used by the assistant generator * wip * wip * wip * fix linter * bump webrick * enhancements * enhancements * Add post_install_message * Views use turbo so we need to add turbo-rails to the host Gemfile * wip * Fixes * Fix this * Fix linter * Bump langchainrb version * Bug fix since the namespace had changed in langchainrb * Fix spec * Update Gemfile.lock * Assistant generator UI (#125) * remove os files and ignore globally * ignore ruby-version * add destroy instructions * test that the views get generated * readme update --------- Co-authored-by: Sergio Bayona <[email protected]>
1 parent dfad638 commit 1655d09

File tree

18 files changed

+665
-11
lines changed

18 files changed

+665
-11
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
/pkg/
77
/spec/reports/
88
/tmp/
9+
.ruby-version
910

1011
# rspec failure tracking
1112
.rspec_status
13+
**/.DS_Store

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,18 @@ prompt.render(adjective: "funny", subject: "elephants")
147147
# => "Tell me a funny joke about elephants."
148148
```
149149

150-
### Assistant Generator - adds assistant capabilities to your ActiveRecord model
150+
### Assistant Generator - adds Langchain::Assistant capabilities to your Rails app
151+
152+
This generator adds Langchain::Assistant-related ActiveRecord models, migrations, controllers, views and route to your Rails app. You can start creating assistants and chatting with them in immediately.
153+
154+
```bash
155+
rails generate langchainrb_rails:assistant --llm=openai
156+
```
157+
158+
Available `--llm` options: `anthropic`, `cohere`, `google_palm`, `google_gemini`, `google_vertex_ai`, `hugging_face`, `llama_cpp`, `mistral_ai`, `ollama`, `openai`, and `replicate`. The selected LLM will be used to generate completions.
159+
160+
To remove the generated files, run:
161+
151162
```bash
152-
rails generate langchainrb_rails:assistant
153-
```
163+
rails destroy langchainrb_rails:assistant
164+
```

lib/langchainrb_overrides/assistant.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def load(id)
5858
llm: ar_assistant.llm,
5959
tools: tools,
6060
instructions: ar_assistant.instructions,
61-
tool_choice: ar_assistant.tool_choice
61+
# Default to auto to match the behavior of the original Langchain::Assistant
62+
tool_choice: ar_assistant.tool_choice || "auto"
6263
)
6364

6465
ar_assistant.messages.each do |ar_message|

lib/langchainrb_rails/generators/langchainrb_rails/assistant_generator.rb

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,60 @@ def migration_version
5151
"[#{::ActiveRecord::VERSION::MAJOR}.#{::ActiveRecord::VERSION::MINOR}]"
5252
end
5353

54+
def create_controller_file
55+
template "assistant/controllers/assistants_controller.rb", "app/controllers/assistants_controller.rb"
56+
end
57+
58+
def create_view_files
59+
template "assistant/views/_message.html.erb", "app/views/assistants/_message.html.erb"
60+
template "assistant/views/_message_form.html.erb", "app/views/assistants/_message_form.html.erb"
61+
template "assistant/views/chat.turbo_stream.erb", "app/views/assistants/chat.turbo_stream.erb"
62+
template "assistant/views/edit.html.erb", "app/views/assistants/edit.html.erb"
63+
template "assistant/views/index.html.erb", "app/views/assistants/index.html.erb"
64+
template "assistant/views/new.html.erb", "app/views/assistants/new.html.erb"
65+
template "assistant/views/show.html.erb", "app/views/assistants/show.html.erb"
66+
end
67+
68+
def add_routes
69+
route <<~EOS
70+
resources :assistants do
71+
member do
72+
post 'chat'
73+
end
74+
end
75+
EOS
76+
end
77+
78+
# TODO: Copy stylesheet into app/assets/stylesheets or whatever the host app uses
79+
def copy_stylesheets
80+
template "assistant/stylesheets/chat.css", "app/assets/stylesheets/chat.css"
81+
end
82+
5483
# TODO: Depending on the LLM provider, we may need to add additional gems
55-
# def add_to_gemfile
56-
# end
84+
def add_to_gemfile
85+
gem_name = "turbo-rails"
86+
87+
if gem_exists?(gem_name)
88+
say_status :skipped, "#{gem_name} already exists in Gemfile"
89+
else
90+
inside Rails.root do
91+
run "bundle add #{gem_name}"
92+
end
93+
end
94+
end
95+
96+
def post_install_message
97+
say "1. Set an environment variable ENV['#{llm.upcase}_API_KEY'] for your #{llm_class}."
98+
say "2. Run `rails db:migrate` to apply the database migrations to create the assistants and messages tables."
99+
say "3. Start your Rails server and navigate to `/assistants` to create your first assistant!"
100+
end
57101

58102
private
59103

104+
def gem_exists?(gem_name)
105+
File.read(Rails.root.join("Gemfile")).include?(gem_name)
106+
end
107+
60108
# @return [String] LLM provider to use
61109
def llm
62110
options["llm"]
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
class AssistantsController < ApplicationController
4+
before_action :set_assistant, only: [:show, :edit, :update, :chat, :destroy]
5+
6+
def index
7+
@assistants = Assistant.all
8+
end
9+
10+
def new
11+
@assistant = Assistant.new
12+
end
13+
14+
def create
15+
@assistant = Assistant.new(assistant_params)
16+
if @assistant.save
17+
redirect_to @assistant, notice: "Assistant was successfully created."
18+
else
19+
render :new
20+
end
21+
end
22+
23+
def show
24+
@assistants = Assistant.all
25+
@assistant = Assistant.find(params[:id])
26+
@messages = @assistant.messages
27+
@message = Message.new
28+
end
29+
30+
def edit
31+
end
32+
33+
def update
34+
if @assistant.update(assistant_params)
35+
redirect_to @assistant, notice: "Assistant was successfully updated."
36+
else
37+
render :edit
38+
end
39+
end
40+
41+
def chat
42+
@assistant = Assistant.find(params[:id])
43+
@message = @assistant.messages.create(role: "user", content: params[:message][:content])
44+
45+
langchain_assistant = Langchain::Assistant.load(@assistant.id)
46+
messages = langchain_assistant.add_message_and_run!(content: params[:message][:content])
47+
response = messages.last
48+
49+
@response = @assistant.messages.create(role: "assistant", content: response.content)
50+
51+
respond_to do |format|
52+
format.turbo_stream
53+
end
54+
end
55+
56+
def destroy
57+
@assistant.destroy
58+
redirect_to assistants_path, notice: "Assistant was successfully deleted."
59+
end
60+
61+
private
62+
63+
def set_assistant
64+
@assistant = Assistant.find(params[:id])
65+
end
66+
67+
def assistant_params
68+
params.require(:assistant).permit(:name, :instructions, :tool_choice)
69+
end
70+
end

lib/langchainrb_rails/generators/langchainrb_rails/templates/assistant/migrations/create_assistants.rb.tt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
22
def change
33
create_table :assistants do |t|
4+
t.string :name, null: false
45
t.string :instructions
56
t.string :tool_choice
6-
t.json :tools
7+
t.json :tools, default: []
78
t.timestamps
89
end
910
end

lib/langchainrb_rails/generators/langchainrb_rails/templates/assistant/migrations/create_messages.rb.tt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
22
def change
33
create_table :messages do |t|
44
t.references :assistant, foreign_key: true
5-
t.string :role
5+
t.string :role, null: false
66
t.text :content
7-
t.json :tool_calls
7+
t.json :tool_calls, default: []
88
t.string :tool_call_id
99
t.timestamps
1010
end

lib/langchainrb_rails/generators/langchainrb_rails/templates/assistant/models/assistant.rb.tt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# frozen_string_literal: true
22

33
class Assistant < ActiveRecord::Base
4-
has_many :messages
4+
has_many :messages, dependent: :destroy
5+
6+
validates :name, presence: true
7+
8+
# TODO: Validate tool_choice
59

610
def llm
711
<%= llm_class %>.new(api_key: ENV["<%= llm.upcase %>_API_KEY"])

lib/langchainrb_rails/generators/langchainrb_rails/templates/assistant/models/message.rb.tt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22

33
class Message < ActiveRecord::Base
44
belongs_to :assistant
5+
6+
validates :role, presence: true
57
end

0 commit comments

Comments
 (0)