layered-assistant-rails 0.3.0 → 0.3.1
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/AGENTS.md +4 -0
- data/README.md +1 -7
- data/app/controllers/layered/assistant/assistants_controller.rb +13 -3
- data/app/controllers/layered/assistant/personas_controller.rb +60 -0
- data/app/models/layered/assistant/assistant.rb +1 -0
- data/app/models/layered/assistant/conversation.rb +3 -2
- data/app/models/layered/assistant/persona.rb +20 -0
- data/app/services/layered/assistant/system_prompt_service.rb +17 -0
- data/app/views/layered/assistant/assistants/_form.html.erb +6 -0
- data/app/views/layered/assistant/personas/_form.html.erb +31 -0
- data/app/views/layered/assistant/personas/edit.html.erb +2 -0
- data/app/views/layered/assistant/personas/index.html.erb +41 -0
- data/app/views/layered/assistant/personas/new.html.erb +2 -0
- data/app/views/layouts/layered/assistant/application.html.erb +1 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20260403000000_create_layered_assistant_personas.rb +13 -0
- data/db/migrate/20260403000001_add_persona_to_layered_assistant_assistants.rb +5 -0
- data/lib/generators/layered/assistant/templates/initializer.rb +2 -4
- data/lib/layered/assistant/version.rb +1 -1
- metadata +10 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8c4d53502a7e91e56f50420d3d16830d3441a49a3a6a5a399be405d10e0c05b4
|
|
4
|
+
data.tar.gz: 6155fe4297f73702449ac22e099692cc17d6582c697f68c0e7b9df8f0f3bc96f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8131ee6e51b4f9417501de38b88af330e1dbd6b0603e4284e56900e37b41c549265d56821b6518846e1d1c95382d4fe186fca8c2d5a450c7c4a17f2a5ac79266
|
|
7
|
+
data.tar.gz: 9ff9c8b830ee1cabaeed1da03332e57f5622ce79104f3d0f2e760be19d2dc503adcc0195bb3eb0d877b9b4a656a8556e6596301b087eb9fb805d619291978e18
|
data/AGENTS.md
CHANGED
|
@@ -39,6 +39,10 @@ You can run the tests with: `bundle exec rake test`
|
|
|
39
39
|
- Tables prefixed `layered_assistant_`
|
|
40
40
|
- Models inherit from `Layered::Assistant::ApplicationRecord`
|
|
41
41
|
|
|
42
|
+
### Ownership and scoping
|
|
43
|
+
|
|
44
|
+
Ownership is enforced at the controller layer via `scoped()`, not with model validations. When a controller action accepts a foreign key for a scoped model (e.g. `persona_id`, `assistant_id`), look up the record through `scoped(Model).find(params[:id])` so that out-of-scope IDs return 404. Do not add model-level validations that duplicate this scoping logic.
|
|
45
|
+
|
|
42
46
|
### Generators
|
|
43
47
|
|
|
44
48
|
Verify dependencies before modifying host app files. Use `inject_into_file` for safe insertion. Check for existing imports to ensure idempotency.
|
data/README.md
CHANGED
|
@@ -106,13 +106,7 @@ The `l_assistant_accessible?` helper evaluates the authorize block without side
|
|
|
106
106
|
|
|
107
107
|
By default, all records are visible to any authorised user. If your application is multi-tenant or you need to restrict which records a user can see, configure a `scope` block in the initialiser.
|
|
108
108
|
|
|
109
|
-
The block receives the model class, runs in controller context, and must return an `ActiveRecord::Relation`.
|
|
110
|
-
|
|
111
|
-
| Model | Description |
|
|
112
|
-
|---|---|
|
|
113
|
-
| `Layered::Assistant::Conversation` | User conversations (has polymorphic `owner`) |
|
|
114
|
-
| `Layered::Assistant::Assistant` | Assistant configurations (has polymorphic `owner`) |
|
|
115
|
-
| `Layered::Assistant::Provider` | API provider credentials (has polymorphic `owner`) |
|
|
109
|
+
The block receives the model class, runs in controller context, and must return an `ActiveRecord::Relation`. All engine models with a polymorphic `owner` association are passed through the scope block.
|
|
116
110
|
|
|
117
111
|
### Scope all owned resources to the current user
|
|
118
112
|
|
|
@@ -3,6 +3,7 @@ module Layered
|
|
|
3
3
|
class AssistantsController < ApplicationController
|
|
4
4
|
before_action :set_assistant, only: [:edit, :update, :destroy]
|
|
5
5
|
before_action :set_models, only: [:new, :create, :edit, :update]
|
|
6
|
+
before_action :set_personas, only: [:new, :create, :edit, :update]
|
|
6
7
|
|
|
7
8
|
def index
|
|
8
9
|
@page_title = "Assistants"
|
|
@@ -15,8 +16,9 @@ module Layered
|
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def create
|
|
18
|
-
@assistant = Assistant.new(assistant_params)
|
|
19
|
+
@assistant = Assistant.new(assistant_params.except(:persona_id))
|
|
19
20
|
@assistant.owner = l_ui_current_user
|
|
21
|
+
@assistant.persona = scoped(Persona).find(assistant_params[:persona_id]) if assistant_params[:persona_id].present?
|
|
20
22
|
|
|
21
23
|
if @assistant.save
|
|
22
24
|
redirect_to layered_assistant.assistants_path, notice: "Assistant was successfully created."
|
|
@@ -30,7 +32,11 @@ module Layered
|
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def update
|
|
33
|
-
if
|
|
35
|
+
if assistant_params.key?(:persona_id)
|
|
36
|
+
@assistant.persona = assistant_params[:persona_id].present? ? scoped(Persona).find(assistant_params[:persona_id]) : nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if @assistant.update(assistant_params.except(:persona_id))
|
|
34
40
|
redirect_to layered_assistant.assistants_path, notice: "Assistant was successfully updated."
|
|
35
41
|
else
|
|
36
42
|
render :edit, status: :unprocessable_entity
|
|
@@ -52,8 +58,12 @@ module Layered
|
|
|
52
58
|
@models = Model.available
|
|
53
59
|
end
|
|
54
60
|
|
|
61
|
+
def set_personas
|
|
62
|
+
@personas = scoped(Persona).by_name
|
|
63
|
+
end
|
|
64
|
+
|
|
55
65
|
def assistant_params
|
|
56
|
-
params.require(:assistant).permit(:name, :description, :instructions, :default_model_id, :public)
|
|
66
|
+
params.require(:assistant).permit(:name, :description, :instructions, :default_model_id, :persona_id, :public)
|
|
57
67
|
end
|
|
58
68
|
end
|
|
59
69
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Layered
|
|
2
|
+
module Assistant
|
|
3
|
+
class PersonasController < ApplicationController
|
|
4
|
+
before_action :set_persona, only: [:edit, :update, :destroy]
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
@page_title = "Personas"
|
|
8
|
+
@pagy, @personas = pagy(scoped(Persona).by_name)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def new
|
|
12
|
+
@page_title = "New persona"
|
|
13
|
+
@persona = Persona.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create
|
|
17
|
+
@persona = Persona.new(persona_params)
|
|
18
|
+
@persona.owner = l_ui_current_user
|
|
19
|
+
|
|
20
|
+
if @persona.save
|
|
21
|
+
redirect_to layered_assistant.personas_path, notice: "Persona was successfully created."
|
|
22
|
+
else
|
|
23
|
+
render :new, status: :unprocessable_entity
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def edit
|
|
28
|
+
@page_title = "Edit persona"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def update
|
|
32
|
+
if @persona.update(persona_params)
|
|
33
|
+
redirect_to layered_assistant.personas_path, notice: "Persona was successfully updated."
|
|
34
|
+
else
|
|
35
|
+
render :edit, status: :unprocessable_entity
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def destroy
|
|
40
|
+
if @persona.destroy
|
|
41
|
+
redirect_to layered_assistant.personas_path, notice: "Persona was successfully deleted."
|
|
42
|
+
else
|
|
43
|
+
redirect_to layered_assistant.personas_path, alert: "Persona could not be deleted: #{@persona.errors.full_messages.to_sentence}."
|
|
44
|
+
end
|
|
45
|
+
rescue ActiveRecord::InvalidForeignKey
|
|
46
|
+
redirect_to layered_assistant.personas_path, alert: "Persona could not be deleted because it is assigned to assistants."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def set_persona
|
|
52
|
+
@persona = scoped(Persona).find(params[:id])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def persona_params
|
|
56
|
+
params.require(:persona).permit(:name, :description, :instructions)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -7,6 +7,7 @@ module Layered
|
|
|
7
7
|
# Associations
|
|
8
8
|
belongs_to :owner, polymorphic: true, optional: true
|
|
9
9
|
belongs_to :default_model, class_name: "Layered::Assistant::Model", optional: true, counter_cache: :assistants_count
|
|
10
|
+
belongs_to :persona, optional: true, counter_cache: :assistants_count
|
|
10
11
|
has_many :conversations, dependent: :destroy
|
|
11
12
|
|
|
12
13
|
# Validations
|
|
@@ -77,9 +77,10 @@ module Layered
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
79
|
def create_system_message
|
|
80
|
-
|
|
80
|
+
prompt = SystemPromptService.new.call(assistant: assistant)
|
|
81
|
+
return if prompt.blank?
|
|
81
82
|
|
|
82
|
-
messages.create!(role: :system, content:
|
|
83
|
+
messages.create!(role: :system, content: prompt)
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
def broadcast_name_updated(old_name)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Layered
|
|
2
|
+
module Assistant
|
|
3
|
+
class Persona < ApplicationRecord
|
|
4
|
+
# UID
|
|
5
|
+
has_secure_token :uid
|
|
6
|
+
|
|
7
|
+
# Associations
|
|
8
|
+
belongs_to :owner, polymorphic: true, optional: true
|
|
9
|
+
has_many :assistants, dependent: :restrict_with_error
|
|
10
|
+
|
|
11
|
+
# Validations
|
|
12
|
+
validates :name, presence: true
|
|
13
|
+
validates :instructions, presence: true
|
|
14
|
+
|
|
15
|
+
# Scopes
|
|
16
|
+
scope :by_name, -> { order(name: :asc, created_at: :desc) }
|
|
17
|
+
scope :by_created_at, -> { order(created_at: :desc) }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Layered
|
|
2
|
+
module Assistant
|
|
3
|
+
class SystemPromptService
|
|
4
|
+
def call(assistant:)
|
|
5
|
+
parts = []
|
|
6
|
+
|
|
7
|
+
if assistant.persona&.instructions.present?
|
|
8
|
+
parts << "**Persona**\n\n#{assistant.persona.instructions}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
parts << assistant.instructions if assistant.instructions.present?
|
|
12
|
+
|
|
13
|
+
parts.join("\n\n").presence
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
<%= render "layered_ui/shared/field_error", object: assistant, field: :instructions %>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
|
+
<div class="l-ui-form__group">
|
|
23
|
+
<%= render "layered_ui/shared/label", form: f, field: :persona_id, name: "Persona", required: false %>
|
|
24
|
+
<%= f.select :persona_id, @personas.map { |p| [p.name, p.id] }, { include_blank: "None" }, class: "l-ui-select" %>
|
|
25
|
+
<%= render "layered_ui/shared/field_error", object: assistant, field: :persona_id %>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
22
28
|
<div class="l-ui-form__group">
|
|
23
29
|
<%= render "layered_ui/shared/label", form: f, field: :default_model_id, name: "Default model", required: false %>
|
|
24
30
|
<%= f.select :default_model_id, @models.map { |m| ["#{m.provider.name} - #{m.name}", m.id] }, { include_blank: "None" }, class: "l-ui-select" %>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%= form_with(model: persona, url: url, html: { class: "l-ui-form" }) do |f| %>
|
|
2
|
+
<%= render "layered_ui/shared/form_errors", item: persona %>
|
|
3
|
+
|
|
4
|
+
<div class="l-ui-form__group">
|
|
5
|
+
<%= render "layered_ui/shared/label", form: f, field: :name, required: true %>
|
|
6
|
+
<%= f.text_field :name, class: "l-ui-form__field" %>
|
|
7
|
+
<%= render "layered_ui/shared/field_error", object: persona, field: :name %>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div class="l-ui-form__group">
|
|
11
|
+
<%= render "layered_ui/shared/label", form: f, field: :description, required: false %>
|
|
12
|
+
<%= f.text_area :description, class: "l-ui-form__field", rows: 3 %>
|
|
13
|
+
<%= render "layered_ui/shared/field_error", object: persona, field: :description %>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="l-ui-form__group">
|
|
17
|
+
<%= render "layered_ui/shared/label", form: f, field: :instructions, required: true %>
|
|
18
|
+
<%= f.text_area :instructions, class: "l-ui-form__field", rows: 5 %>
|
|
19
|
+
<p class="l-ui-form__hint">Shape the personality and tone of conversations, used alongside the assistant's own instructions. e.g. "Reply in British English with a formal tone"</p>
|
|
20
|
+
<%= render "layered_ui/shared/field_error", object: persona, field: :instructions %>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="l-ui-container--spread l-ui-utility--mt-2xl">
|
|
24
|
+
<% if persona.persisted? %>
|
|
25
|
+
<%= link_to "Delete", layered_assistant.persona_path(persona), class: "l-ui-button--outline-danger", data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>
|
|
26
|
+
<% else %>
|
|
27
|
+
<span></span>
|
|
28
|
+
<% end %>
|
|
29
|
+
<%= f.submit persona.new_record? ? "Create" : "Update", class: "l-ui-button--primary" %>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<div class="l-ui-container--spread">
|
|
2
|
+
<h1>Personas</h1>
|
|
3
|
+
<%= link_to "New", layered_assistant.new_persona_path, class: "l-ui-button--primary" %>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="l-ui-container--table l-ui-utility--mt-lg">
|
|
7
|
+
<table class="l-ui-table">
|
|
8
|
+
<caption class="l-ui-sr-only">Personas</caption>
|
|
9
|
+
<thead class="l-ui-table__header">
|
|
10
|
+
<tr>
|
|
11
|
+
<th scope="col" class="l-ui-table__header-cell">Name</th>
|
|
12
|
+
<th scope="col" class="l-ui-table__header-cell">Description</th>
|
|
13
|
+
<th scope="col" class="l-ui-table__header-cell">Assistants</th>
|
|
14
|
+
<th scope="col" class="l-ui-table__header-cell--action">Actions</th>
|
|
15
|
+
</tr>
|
|
16
|
+
</thead>
|
|
17
|
+
|
|
18
|
+
<tbody class="l-ui-table__body">
|
|
19
|
+
<% @personas.each do |persona| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<th scope="row" class="l-ui-table__cell--primary">
|
|
22
|
+
<%= persona.name %>
|
|
23
|
+
</th>
|
|
24
|
+
<td class="l-ui-table__cell">
|
|
25
|
+
<%= truncate(persona.description, length: 60) %>
|
|
26
|
+
</td>
|
|
27
|
+
<td class="l-ui-table__cell">
|
|
28
|
+
<%= persona.assistants_count %>
|
|
29
|
+
</td>
|
|
30
|
+
<td class="l-ui-table__cell--action">
|
|
31
|
+
<%= link_to "Edit", layered_assistant.edit_persona_path(persona) %>
|
|
32
|
+
</td>
|
|
33
|
+
</tr>
|
|
34
|
+
<% end %>
|
|
35
|
+
</tbody>
|
|
36
|
+
</table>
|
|
37
|
+
|
|
38
|
+
<div class="l-ui-utility--mt-lg">
|
|
39
|
+
<%= l_ui_pagy(@pagy) %>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
<% if l_assistant_accessible? %>
|
|
10
10
|
<%= l_ui_navigation_item "Setup", layered_assistant.root_path %>
|
|
11
11
|
<%= l_ui_navigation_item "Providers", layered_assistant.providers_path %>
|
|
12
|
+
<%= l_ui_navigation_item "Personas", layered_assistant.personas_path %>
|
|
12
13
|
<%= l_ui_navigation_item "Assistants", layered_assistant.assistants_path %>
|
|
13
14
|
<%= l_ui_navigation_item "Conversations", layered_assistant.conversations_path %>
|
|
14
15
|
<% else %>
|
data/config/routes.rb
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class CreateLayeredAssistantPersonas < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :layered_assistant_personas, if_not_exists: true do |t|
|
|
4
|
+
t.string :uid, null: false, index: { unique: true }
|
|
5
|
+
t.references :owner, polymorphic: true
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.text :description
|
|
8
|
+
t.text :instructions
|
|
9
|
+
t.bigint :assistants_count, default: 0, null: false
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -33,10 +33,8 @@
|
|
|
33
33
|
# have access to current_user and other helpers. Return an ActiveRecord
|
|
34
34
|
# relation (e.g. model_class.where(...) or model_class.all).
|
|
35
35
|
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# - Layered::Assistant::Assistant (has polymorphic owner)
|
|
39
|
-
# - Layered::Assistant::Provider (has polymorphic owner)
|
|
36
|
+
# All engine models with a polymorphic owner association are passed through
|
|
37
|
+
# the scope block.
|
|
40
38
|
#
|
|
41
39
|
# Scope all owned resources to the current user:
|
|
42
40
|
#
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: layered-assistant-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- layered.ai
|
|
@@ -313,6 +313,7 @@ files:
|
|
|
313
313
|
- app/controllers/layered/assistant/models_controller.rb
|
|
314
314
|
- app/controllers/layered/assistant/panel/conversations_controller.rb
|
|
315
315
|
- app/controllers/layered/assistant/panel/messages_controller.rb
|
|
316
|
+
- app/controllers/layered/assistant/personas_controller.rb
|
|
316
317
|
- app/controllers/layered/assistant/providers_controller.rb
|
|
317
318
|
- app/controllers/layered/assistant/public/application_controller.rb
|
|
318
319
|
- app/controllers/layered/assistant/public/assistants_controller.rb
|
|
@@ -339,6 +340,7 @@ files:
|
|
|
339
340
|
- app/models/layered/assistant/conversation.rb
|
|
340
341
|
- app/models/layered/assistant/message.rb
|
|
341
342
|
- app/models/layered/assistant/model.rb
|
|
343
|
+
- app/models/layered/assistant/persona.rb
|
|
342
344
|
- app/models/layered/assistant/provider.rb
|
|
343
345
|
- app/services/layered/assistant/chunk_parser.rb
|
|
344
346
|
- app/services/layered/assistant/chunk_service.rb
|
|
@@ -349,6 +351,7 @@ files:
|
|
|
349
351
|
- app/services/layered/assistant/messages_service.rb
|
|
350
352
|
- app/services/layered/assistant/models/create_service.rb
|
|
351
353
|
- app/services/layered/assistant/response_timer.rb
|
|
354
|
+
- app/services/layered/assistant/system_prompt_service.rb
|
|
352
355
|
- app/services/layered/assistant/token_estimator.rb
|
|
353
356
|
- app/views/layered/assistant/assistants/_form.html.erb
|
|
354
357
|
- app/views/layered/assistant/assistants/edit.html.erb
|
|
@@ -374,6 +377,10 @@ files:
|
|
|
374
377
|
- app/views/layered/assistant/panel/conversations/show.html.erb
|
|
375
378
|
- app/views/layered/assistant/panel/messages/_composer.html.erb
|
|
376
379
|
- app/views/layered/assistant/panel/messages/create.turbo_stream.erb
|
|
380
|
+
- app/views/layered/assistant/personas/_form.html.erb
|
|
381
|
+
- app/views/layered/assistant/personas/edit.html.erb
|
|
382
|
+
- app/views/layered/assistant/personas/index.html.erb
|
|
383
|
+
- app/views/layered/assistant/personas/new.html.erb
|
|
377
384
|
- app/views/layered/assistant/providers/_form.html.erb
|
|
378
385
|
- app/views/layered/assistant/providers/edit.html.erb
|
|
379
386
|
- app/views/layered/assistant/providers/index.html.erb
|
|
@@ -400,6 +407,8 @@ files:
|
|
|
400
407
|
- db/migrate/20260315000000_add_stopped_to_layered_assistant_messages.rb
|
|
401
408
|
- db/migrate/20260315100000_add_response_timing_to_layered_assistant_messages.rb
|
|
402
409
|
- db/migrate/20260317000000_normalise_provider_protocol_values.rb
|
|
410
|
+
- db/migrate/20260403000000_create_layered_assistant_personas.rb
|
|
411
|
+
- db/migrate/20260403000001_add_persona_to_layered_assistant_assistants.rb
|
|
403
412
|
- db/migrate/20260406000000_rename_system_prompt_to_instructions.rb
|
|
404
413
|
- lib/generators/layered/assistant/install_generator.rb
|
|
405
414
|
- lib/generators/layered/assistant/migrations_generator.rb
|