layered-assistant-rails 0.4.1 → 0.5.0
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/.claude/skills/layered-assistant-rails/SKILL.md +207 -0
- data/AGENTS.md +1 -1
- data/README.md +18 -0
- data/app/assets/images/layered_assistant/icon_assistants.svg +3 -0
- data/app/assets/images/layered_assistant/icon_conversations.svg +3 -0
- data/app/assets/images/layered_assistant/icon_personas.svg +3 -0
- data/app/assets/images/layered_assistant/icon_providers.svg +3 -0
- data/app/assets/images/layered_assistant/icon_skills.svg +3 -0
- data/app/assets/images/layered_assistant/icon_spanner.svg +3 -0
- data/app/views/layouts/layered/assistant/application.html.erb +11 -7
- data/lib/generators/layered/assistant/install_agent_skill_generator.rb +26 -0
- data/lib/layered/assistant/engine.rb +1 -0
- data/lib/layered/assistant/version.rb +1 -1
- metadata +16 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9419d936b5247ec519e481b02b7ead93a0e85bd6720a7b4298d145810c1405be
|
|
4
|
+
data.tar.gz: 5f9058cdae99fa50b3bf704853b74205f9a544e8c8430611ceb6ba1a509356bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5111d8c91517082ac5ab5eea935df4fbf73f0952c7455fcf6ac98f1fadab19f842aa0bf2483c60cdf1d8aaf2cfdb2cb812f488e7352195586038337f3e2314a
|
|
7
|
+
data.tar.gz: 3776256743b2734f9ae369508770e8cdc327e17299de34d01af376ba594485b4e55d2b160ce4b4820968c657fedcca2ede227067810a7dcb6f134e29dc5dd7ca
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: layered-assistant-rails
|
|
3
|
+
description: Installs, configures, and builds with the layered-assistant-rails gem - a Rails 8+ engine providing AI assistant UI, conversations, providers, models, personas and skills, with a side-panel chat. Use when adding layered-assistant-rails to a Rails app, mounting the engine, configuring authorization and scoping, embedding the assistant panel, or troubleshooting setup.
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
compatibility: Requires Ruby on Rails >= 8.0, Ruby >= 3.2, layered-ui-rails >= 0.4, importmap-rails >= 2.0, stimulus-rails >= 1.0, turbo-rails
|
|
6
|
+
metadata:
|
|
7
|
+
author: layered.ai
|
|
8
|
+
version: "1.0"
|
|
9
|
+
source: https://github.com/layered-ai-public/layered-assistant-rails
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# layered-assistant-rails
|
|
13
|
+
|
|
14
|
+
A Rails 8+ engine providing an AI assistant: conversations, messages with streaming, configurable providers (Anthropic, OpenAI), models, personas, skills, and a side-panel chat that drops into any layered-ui-rails layout.
|
|
15
|
+
|
|
16
|
+
It builds on `layered-ui-rails` for layout, components, and theming. Install that gem first (or let this generator install it for you).
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bundle add layered-assistant-rails
|
|
22
|
+
bin/rails generate layered:assistant:install
|
|
23
|
+
bin/rails db:migrate
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The install generator:
|
|
27
|
+
|
|
28
|
+
1. Verifies `layered-ui-rails` is installed - invokes its installer if not.
|
|
29
|
+
2. Adds `import "layered_assistant"` to `app/javascript/application.js` (after the `layered_ui` import).
|
|
30
|
+
3. Creates `config/initializers/layered_assistant.rb` with example `authorize` and `scope` blocks.
|
|
31
|
+
4. Mounts the engine at `/layered/assistant` in `config/routes.rb`.
|
|
32
|
+
5. Copies migrations into the host app via the `layered:assistant:migrations` generator.
|
|
33
|
+
|
|
34
|
+
After installation, configure the initializer (see below) - **routes return 403 until an `authorize` block is set**. Then visit `/layered/assistant` to set up providers, models, personas, skills and assistants.
|
|
35
|
+
|
|
36
|
+
## Authorization
|
|
37
|
+
|
|
38
|
+
All non-public engine routes are gated by an `authorize` block. The block runs in controller context, so you have access to `current_user`, `request`, `redirect_to`, `head`, `main_app`, etc.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# config/initializers/layered_assistant.rb
|
|
42
|
+
|
|
43
|
+
# Require sign-in (Devise):
|
|
44
|
+
Layered::Assistant.authorize do
|
|
45
|
+
redirect_to main_app.new_user_session_path unless user_signed_in?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Restrict to admins:
|
|
49
|
+
Layered::Assistant.authorize do
|
|
50
|
+
head :forbidden unless current_user&.admin?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Allow all (no-op):
|
|
54
|
+
Layered::Assistant.authorize do
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Until configured, every request returns 403. Public routes under `/layered/assistant/public/...` are exempt - use these to expose specific assistants to anonymous visitors.
|
|
59
|
+
|
|
60
|
+
## Scoping (multi-tenant ownership)
|
|
61
|
+
|
|
62
|
+
Engine models with a polymorphic `owner` association (assistants, personas, providers, models, skills, conversations) can be scoped per request. The block receives the model class and returns an `ActiveRecord::Relation`:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
Layered::Assistant.scope do |model_class|
|
|
66
|
+
model_class.where(owner: current_user)
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Scope only conversations, leave the rest unscoped:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
Layered::Assistant.scope do |model_class|
|
|
74
|
+
if model_class == Layered::Assistant::Conversation
|
|
75
|
+
model_class.where(owner: current_user)
|
|
76
|
+
else
|
|
77
|
+
model_class.all
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Ownership is enforced **at the controller layer via `scoped()`**, not via model validations. Out-of-scope IDs return 404.
|
|
83
|
+
|
|
84
|
+
## Optional settings
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
Layered::Assistant.log_errors = true # log API errors to stdout
|
|
88
|
+
Layered::Assistant.api_request_timeout = 210 # total streaming API timeout (seconds)
|
|
89
|
+
Layered::Assistant.skip_db_encryption = true # dev/test only - skip encryption on Provider#secret
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`Provider#secret` is encrypted with Rails encrypted attributes, so the host app must have `bin/rails db:encryption:init` keys configured (or set `skip_db_encryption = true` for dev/test).
|
|
93
|
+
|
|
94
|
+
## Mounting the assistant panel
|
|
95
|
+
|
|
96
|
+
The engine ships a side-panel chat that plugs into the `layered-ui-rails` panel slot. Use `PanelHelper` inside your layout's `content_for` blocks (always **above** the layout render call):
|
|
97
|
+
|
|
98
|
+
```erb
|
|
99
|
+
<% content_for :l_ui_panel_heading do %>
|
|
100
|
+
<%= layered_assistant_panel_header %>
|
|
101
|
+
<% end %>
|
|
102
|
+
|
|
103
|
+
<% content_for :l_ui_panel_body do %>
|
|
104
|
+
<%= layered_assistant_panel_body %>
|
|
105
|
+
<% end %>
|
|
106
|
+
|
|
107
|
+
<%= render template: "layouts/layered_ui/application" %>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The body lazy-loads the conversation list from `panel_conversations_path` via a Turbo Frame.
|
|
111
|
+
|
|
112
|
+
For a public (unauthenticated) panel scoped to one assistant:
|
|
113
|
+
|
|
114
|
+
```erb
|
|
115
|
+
<% content_for :l_ui_panel_body do %>
|
|
116
|
+
<%= layered_assistant_public_panel_body(assistant: @assistant) %>
|
|
117
|
+
<% end %>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## View helpers
|
|
121
|
+
|
|
122
|
+
| Helper | Purpose |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `layered_assistant_panel_header(**opts, &block)` | Turbo frame for the panel header |
|
|
125
|
+
| `layered_assistant_panel_body(**opts)` | Turbo frame that loads the authenticated panel conversations |
|
|
126
|
+
| `layered_assistant_public_panel_body(assistant:, **opts)` | Turbo frame for an unauthenticated single-assistant panel |
|
|
127
|
+
| `l_assistant_accessible?` | Returns true if the current request would pass the `authorize` block - useful for hiding the panel from unauthorised users |
|
|
128
|
+
|
|
129
|
+
Example - only render the panel for users who can access it:
|
|
130
|
+
|
|
131
|
+
```erb
|
|
132
|
+
<% if l_assistant_accessible? %>
|
|
133
|
+
<% content_for :l_ui_panel_heading do %>
|
|
134
|
+
<%= layered_assistant_panel_header %>
|
|
135
|
+
<% end %>
|
|
136
|
+
<% content_for :l_ui_panel_body do %>
|
|
137
|
+
<%= layered_assistant_panel_body %>
|
|
138
|
+
<% end %>
|
|
139
|
+
<% end %>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Models
|
|
143
|
+
|
|
144
|
+
All under `Layered::Assistant::*`, tables prefixed `layered_assistant_`. Inherit from `Layered::Assistant::ApplicationRecord`.
|
|
145
|
+
|
|
146
|
+
| Model | Purpose |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `Provider` | API provider config (Anthropic, OpenAI). Holds the encrypted `secret` (API key) |
|
|
149
|
+
| `Model` | A specific model offered by a `Provider` (e.g. `claude-opus-4-7`) |
|
|
150
|
+
| `Persona` | Reusable system prompt / character |
|
|
151
|
+
| `Skill` | A capability that can be attached to assistants |
|
|
152
|
+
| `Assistant` | A configured assistant: model + persona + skills |
|
|
153
|
+
| `AssistantSkill` | Join between assistant and skill |
|
|
154
|
+
| `Conversation` | A chat session with an assistant, owned polymorphically |
|
|
155
|
+
| `Message` | A single message in a conversation; supports streaming |
|
|
156
|
+
|
|
157
|
+
Enums are stored as **strings**, not integers.
|
|
158
|
+
|
|
159
|
+
## Routes
|
|
160
|
+
|
|
161
|
+
Mounted at `/layered/assistant` by default. Top-level resources: `personas`, `skills`, `assistants` (with nested `conversations`), `providers` (with nested `models`), `conversations` (with nested `messages` and a `stop` member route).
|
|
162
|
+
|
|
163
|
+
The engine also exposes:
|
|
164
|
+
|
|
165
|
+
- `panel/conversations` and `panel/conversations/:id/messages` - the authenticated side-panel API
|
|
166
|
+
- `public/assistants`, `public/conversations`, `public/panel/conversations` - unauthenticated entry points for embedding a single assistant on a public page
|
|
167
|
+
|
|
168
|
+
Use `layered_assistant.<route>_path` from the host app, or `main_app.<route>_path` from inside engine views.
|
|
169
|
+
|
|
170
|
+
## JavaScript
|
|
171
|
+
|
|
172
|
+
Stimulus controllers are registered automatically via importmap once `import "layered_assistant"` is in `application.js`:
|
|
173
|
+
|
|
174
|
+
| Identifier | Purpose |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `composer` | Message composer (textarea autosize, submit-on-enter) |
|
|
177
|
+
| `messages` | Message list rendering and scroll behaviour |
|
|
178
|
+
| `panel` | Assistant side-panel state |
|
|
179
|
+
| `panel-nav` | Conversation list navigation inside the panel |
|
|
180
|
+
| `conversation-select` | Conversation picker |
|
|
181
|
+
| `provider-template` | Provider form prefill from a template |
|
|
182
|
+
|
|
183
|
+
`message_streaming.js` wires SSE streaming for assistant replies.
|
|
184
|
+
|
|
185
|
+
## Styling
|
|
186
|
+
|
|
187
|
+
The engine renders inside `layered-ui-rails` layouts and uses only `l-ui-` classes - no host-app Tailwind utilities are required, and **no engine-only Tailwind classes leak into views** (the host's Tailwind build does not scan engine view files). If you customise the look, theme via `layered-ui-rails` CSS custom properties.
|
|
188
|
+
|
|
189
|
+
## Conventions
|
|
190
|
+
|
|
191
|
+
- **Locale**: en-GB unless a technical standard dictates otherwise.
|
|
192
|
+
- **Ownership**: enforce via `scoped()` in controllers, not model validations.
|
|
193
|
+
- **No bundler**: importmap only.
|
|
194
|
+
- **Accessibility**: WCAG 2.2 AA - tables include `<caption>`, `scope="col"`/`scope="row"`, etc.
|
|
195
|
+
|
|
196
|
+
## Common issues
|
|
197
|
+
|
|
198
|
+
- **All routes return 403** - no `authorize` block is configured. Edit `config/initializers/layered_assistant.rb`.
|
|
199
|
+
- **Provider creation fails with encryption error** - run `bin/rails db:encryption:init` and add the keys to credentials, or set `Layered::Assistant.skip_db_encryption = true` for dev/test.
|
|
200
|
+
- **Panel body never loads** - `turbo-rails` must be installed and `layered-ui-rails` must be mounted in the layout. Check `import "@hotwired/turbo-rails"` is present.
|
|
201
|
+
- **`layered_assistant` JS controllers missing** - ensure `import "layered_assistant"` is in `app/javascript/application.js` (added by the install generator, after the `layered_ui` import).
|
|
202
|
+
- **Cross-tenant records visible** - configure `Layered::Assistant.scope` to filter by `owner`.
|
|
203
|
+
|
|
204
|
+
## Further reference
|
|
205
|
+
|
|
206
|
+
- Repository: https://github.com/layered-ai-public/layered-assistant-rails
|
|
207
|
+
- Companion gem: `layered-ui-rails` - layout, components, helpers (skill `layered-ui-rails`)
|
data/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ This file provides guidance to AI agents when working with code in this reposito
|
|
|
6
6
|
|
|
7
7
|
**layered-assistant-rails** is a Rails 8+ engine gem (`Layered::Assistant`) providing AI assistant UI components. It uses `isolate_namespace Layered::Assistant` and distributes JS (importmap) to host applications via a generator.
|
|
8
8
|
|
|
9
|
-
Requires Rails >= 8.0.0, Ruby >= 3.
|
|
9
|
+
Requires Rails >= 8.0.0, Ruby >= 3.3.0. Depends on sibling gem `layered-ui-rails` (path dependency at `../layered-ui-rails`).
|
|
10
10
|
|
|
11
11
|
## Architecture
|
|
12
12
|
|
data/README.md
CHANGED
|
@@ -15,6 +15,24 @@ An open source Rails 8+ engine built on [layered-ui-rails](https://github.com/la
|
|
|
15
15
|
- Ruby on Rails >= 8.0
|
|
16
16
|
- [layered-ui-rails](https://github.com/layered-ai-public/layered-ui-rails) installed in the host app
|
|
17
17
|
|
|
18
|
+
## Agent skill
|
|
19
|
+
|
|
20
|
+
An [agent skill](https://agentskills.io) is included so AI coding agents can work with `layered-assistant-rails` in your project. Once installed, the agent can handle the full setup - just ask it to add `layered-assistant-rails` to your app and it will install the gem, run the generator, and configure your layout.
|
|
21
|
+
|
|
22
|
+
**Project install** - scoped to a single repo, available to all contributors:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bin/rails generate layered:assistant:install_agent_skill
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Global install** - available across all your projects:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
./install-skill.sh
|
|
32
|
+
# or install remotely without cloning the repo:
|
|
33
|
+
curl -fsSL https://raw.githubusercontent.com/layered-ai-public/layered-assistant-rails/main/install-skill.sh | sh
|
|
34
|
+
```
|
|
35
|
+
|
|
18
36
|
## Installation
|
|
19
37
|
|
|
20
38
|
Add to your Gemfile:
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12a7.5 7.5 0 0 0-15 0v5.25a1.5 1.5 0 0 0 1.5 1.5h1.5a1.5 1.5 0 0 0 1.5-1.5V13.5a1.5 1.5 0 0 0-1.5-1.5H4.5m15 0h-3a1.5 1.5 0 0 0-1.5 1.5v3.75a1.5 1.5 0 0 0 1.5 1.5h.75m2.25-5.25v6a3 3 0 0 1-3 3h-3" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M8.625 9.75a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375m-13.5 3.01c0 1.6 1.123 2.994 2.707 3.227 1.087.16 2.185.283 3.293.369V21l4.184-4.183a1.14 1.14 0 0 1 .778-.332 48.294 48.294 0 0 0 5.83-.498c1.585-.233 2.708-1.626 2.708-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 0 0-2.456 2.456ZM16.894 20.567 16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z" />
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437 1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008Z" />
|
|
3
|
+
</svg>
|
|
@@ -7,14 +7,18 @@
|
|
|
7
7
|
<% content_for :l_ui_navigation_items do %>
|
|
8
8
|
<%= render "layouts/layered/assistant/host_navigation" %>
|
|
9
9
|
<% if l_assistant_accessible? %>
|
|
10
|
-
<%=
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
<%= l_ui_navigation_section do %>
|
|
11
|
+
<%= l_ui_navigation_item "Setup", layered_assistant.root_path, icon_path: "layered_assistant/icon_spanner.svg" %>
|
|
12
|
+
<%= l_ui_navigation_item "Providers", layered_assistant.providers_path, icon_path: "layered_assistant/icon_providers.svg" %>
|
|
13
|
+
<%= l_ui_navigation_item "Personas", layered_assistant.personas_path, icon_path: "layered_assistant/icon_personas.svg" %>
|
|
14
|
+
<%= l_ui_navigation_item "Skills", layered_assistant.skills_path, icon_path: "layered_assistant/icon_skills.svg" %>
|
|
15
|
+
<%= l_ui_navigation_item "Assistants", layered_assistant.assistants_path, icon_path: "layered_assistant/icon_assistants.svg" %>
|
|
16
|
+
<%= l_ui_navigation_item "Conversations", layered_assistant.conversations_path, icon_path: "layered_assistant/icon_conversations.svg" %>
|
|
17
|
+
<% end %>
|
|
16
18
|
<% else %>
|
|
17
|
-
<%=
|
|
19
|
+
<%= l_ui_navigation_section do %>
|
|
20
|
+
<%= l_ui_navigation_item "Assistants", layered_assistant.public_assistants_path, icon_path: "layered_assistant/icon_assistants.svg" %>
|
|
21
|
+
<% end %>
|
|
18
22
|
<% end %>
|
|
19
23
|
<% end %>
|
|
20
24
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Layered
|
|
2
|
+
module Assistant
|
|
3
|
+
module Generators
|
|
4
|
+
class InstallAgentSkillGenerator < Rails::Generators::Base
|
|
5
|
+
desc "Copy the layered-assistant-rails agent skill into the host application"
|
|
6
|
+
|
|
7
|
+
def self.source_root
|
|
8
|
+
Layered::Assistant::Engine.root
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def copy_skill
|
|
12
|
+
skill_source = File.join(self.class.source_root, ".claude/skills/layered-assistant-rails")
|
|
13
|
+
skill_dest = ".claude/skills/layered-assistant-rails"
|
|
14
|
+
|
|
15
|
+
directory skill_source, skill_dest
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def show_instructions
|
|
19
|
+
say ""
|
|
20
|
+
say "Agent skill installed to .claude/skills/layered-assistant-rails/", :green
|
|
21
|
+
say ""
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -15,6 +15,7 @@ module Layered
|
|
|
15
15
|
|
|
16
16
|
initializer "layered-assistant-rails.assets" do |app|
|
|
17
17
|
app.config.assets.paths << Engine.root.join("app/javascript")
|
|
18
|
+
app.config.assets.paths << Engine.root.join("app/assets/images")
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
initializer "layered-assistant-rails.helpers" do
|
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.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- layered.ai
|
|
@@ -113,14 +113,14 @@ dependencies:
|
|
|
113
113
|
requirements:
|
|
114
114
|
- - "~>"
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '0.
|
|
116
|
+
version: '0.10'
|
|
117
117
|
type: :runtime
|
|
118
118
|
prerelease: false
|
|
119
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
120
|
requirements:
|
|
121
121
|
- - "~>"
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '0.
|
|
123
|
+
version: '0.10'
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
125
|
name: propshaft
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -297,11 +297,18 @@ executables: []
|
|
|
297
297
|
extensions: []
|
|
298
298
|
extra_rdoc_files: []
|
|
299
299
|
files:
|
|
300
|
+
- ".claude/skills/layered-assistant-rails/SKILL.md"
|
|
300
301
|
- AGENTS.md
|
|
301
302
|
- LICENSE
|
|
302
303
|
- NOTICE
|
|
303
304
|
- README.md
|
|
304
305
|
- Rakefile
|
|
306
|
+
- app/assets/images/layered_assistant/icon_assistants.svg
|
|
307
|
+
- app/assets/images/layered_assistant/icon_conversations.svg
|
|
308
|
+
- app/assets/images/layered_assistant/icon_personas.svg
|
|
309
|
+
- app/assets/images/layered_assistant/icon_providers.svg
|
|
310
|
+
- app/assets/images/layered_assistant/icon_skills.svg
|
|
311
|
+
- app/assets/images/layered_assistant/icon_spanner.svg
|
|
305
312
|
- app/controllers/concerns/layered/assistant/message_creation.rb
|
|
306
313
|
- app/controllers/concerns/layered/assistant/public/session_conversations.rb
|
|
307
314
|
- app/controllers/concerns/layered/assistant/stoppable_response.rb
|
|
@@ -418,6 +425,7 @@ files:
|
|
|
418
425
|
- db/migrate/20260406000000_rename_system_prompt_to_instructions.rb
|
|
419
426
|
- db/migrate/20260406000001_create_layered_assistant_skills.rb
|
|
420
427
|
- db/migrate/20260406000002_create_layered_assistant_assistant_skills.rb
|
|
428
|
+
- lib/generators/layered/assistant/install_agent_skill_generator.rb
|
|
421
429
|
- lib/generators/layered/assistant/install_generator.rb
|
|
422
430
|
- lib/generators/layered/assistant/migrations_generator.rb
|
|
423
431
|
- lib/generators/layered/assistant/templates/initializer.rb
|
|
@@ -431,8 +439,11 @@ licenses:
|
|
|
431
439
|
metadata:
|
|
432
440
|
homepage_uri: https://www.layered.ai
|
|
433
441
|
source_code_uri: https://github.com/layered-ai-public/layered-assistant-rails
|
|
434
|
-
changelog_uri: https://github.com/layered-ai-public/layered-assistant-rails/blob/main/CHANGELOG.md
|
|
435
442
|
bug_tracker_uri: https://github.com/layered-ai-public/layered-assistant-rails/issues
|
|
443
|
+
changelog_uri: https://github.com/layered-ai-public/layered-assistant-rails/blob/main/CHANGELOG.md
|
|
444
|
+
documentation_uri: https://layered-assistant-rails.layered.ai/
|
|
445
|
+
discord_uri: https://discord.gg/aCGqz9Bx
|
|
446
|
+
rubygems_mfa_required: 'true'
|
|
436
447
|
post_install_message: |
|
|
437
448
|
To complete installation, run:
|
|
438
449
|
|
|
@@ -457,7 +468,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
457
468
|
requirements:
|
|
458
469
|
- - ">="
|
|
459
470
|
- !ruby/object:Gem::Version
|
|
460
|
-
version: 3.
|
|
471
|
+
version: 3.3.0
|
|
461
472
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
462
473
|
requirements:
|
|
463
474
|
- - ">="
|