rails-agent-stack 0.2.3 → 0.2.4
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 +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +5 -5
- data/docs/AGENTS.md +9 -6
- data/lib/generators/rails_agents/agent/agent_generator.rb +7 -0
- data/lib/generators/rails_agents/agent/templates/agent_database.rb.tt +8 -32
- data/lib/generators/rails_agents/agent/templates/imports.yml.tt +2 -2
- data/lib/generators/rails_agents/agent/templates/prompt_database.md.tt +10 -8
- data/lib/generators/rails_agents/install/install_generator.rb +5 -4
- data/lib/generators/rails_agents/install/templates/AGENTS.md.tt +3 -3
- data/lib/generators/rails_agents/install/templates/library_README.md.tt +8 -4
- data/lib/generators/rails_agents/install/templates/rails_agents_autoload.rb.tt +3 -1
- data/lib/rails_agents/cli.rb +1 -1
- data/lib/rails_agents/library_imports.rb +29 -11
- data/lib/rails_agents/version.rb +1 -1
- data/rails-agent-stack.gemspec +1 -1
- data/spec/generators/agent_generator_spec.rb +10 -9
- data/spec/rails_agents/library_imports_spec.rb +29 -11
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20b490c75e044e2e9255dad04d19a5d4f91a3a3deacba5f2f5732c00df5ebd9c
|
|
4
|
+
data.tar.gz: fd73c3c31a38596cfb27be72e67d238c5c38d94a6b558e06c1a80f5d865460bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2976710722d70556f2f1cc44008e4ad57f2d31166d4135f7cc73561b43c47c567c178315a38287598bd3e57ccf3575664229456e1a56a272226e2930a1add108
|
|
7
|
+
data.tar.gz: 80a5e64548a04bce6df42211b01767c3604a6fe63a8de12e743ff967972ea7db762079029f283cd895722ac7a031558487c7dc4347e878aa326bda53c37465a5
|
data/AGENTS.md
CHANGED
|
@@ -13,6 +13,6 @@ Quick start:
|
|
|
13
13
|
|
|
14
14
|
Four taxonomy types: **Knowledge**, **Workflow**, **Operations**, **Monitoring**.
|
|
15
15
|
|
|
16
|
-
Capabilities: **Tools**, **Skills**, **Packages** (Skills.sh / APM / Smithery), **Connectors**, **Knowledge**, plus
|
|
16
|
+
Capabilities: **Tools**, **Skills**, **Packages** (Skills.sh / APM / Smithery), **Connectors**, **Knowledge**, plus `app/agents/shared/` reuse.
|
|
17
17
|
|
|
18
18
|
Run responses: prefer `result.output_text` (Markdown) and optional `result.output_data` — see [docs/AGENTS.md](docs/AGENTS.md#run-response-schema-integrate-into-product) and https://rails-agent.com/docs/run-response.
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `rails-agent-stack` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.4] - 2026-08-05
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Shared capabilities live under `app/agents/shared/` (one tree with agents).
|
|
10
|
+
Fresh installs no longer create sibling `app/agents_library/`.
|
|
11
|
+
- `imports.yml` prefers `from: shared/...`; legacy `from: library/...` and
|
|
12
|
+
existing `app/agents_library/` installs still resolve.
|
|
13
|
+
- Agent generator rejects reserved slugs `shared` and `library`.
|
|
14
|
+
|
|
5
15
|
## [0.2.3] - 2026-08-05
|
|
6
16
|
|
|
7
17
|
### Fixed
|
data/README.md
CHANGED
|
@@ -80,7 +80,7 @@ Positioning in one line: **most advanced agentic platform for Ruby on Rails**
|
|
|
80
80
|
| **Memory** | Conversation memory (Mem0-backed), on by default |
|
|
81
81
|
| **Guardrails** | Model access, prompt injection, sensitive info |
|
|
82
82
|
| **Playbooks** | Proven scaffolds you customize locally |
|
|
83
|
-
| **
|
|
83
|
+
| **Shared** | Share tools, skills, packages, knowledge, connectors (`app/agents/shared/` + `imports.yml`) |
|
|
84
84
|
|
|
85
85
|
### Test
|
|
86
86
|
|
|
@@ -141,7 +141,7 @@ Connect your company workspace at `/agents`, then scaffold a database Knowledge
|
|
|
141
141
|
bin/rails generate rails_agents:agent store_assistant --type knowledge --database
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
**Zeitwerk:** fresh installs add `config/initializers/rails_agents_autoload.rb` so `app/agents/`
|
|
144
|
+
**Zeitwerk:** fresh installs add `config/initializers/rails_agents_autoload.rb` so `app/agents/` (including `shared/`) are agent assets, not application namespaces.
|
|
145
145
|
|
|
146
146
|
External coding agents (Cursor, Claude Code, Codex): start with **[docs/AGENTS.md](docs/AGENTS.md)**.
|
|
147
147
|
|
|
@@ -178,7 +178,7 @@ end
|
|
|
178
178
|
app/agents/store_assistant/
|
|
179
179
|
├── agent.rb # RailsAgents::KnowledgeAgent subclass
|
|
180
180
|
├── prompt.md # System prompt
|
|
181
|
-
├── imports.yml # Optional
|
|
181
|
+
├── imports.yml # Optional shared attachments
|
|
182
182
|
├── tools/ # Optional extracted tools
|
|
183
183
|
├── skills/ # Composable behaviors
|
|
184
184
|
├── packages/ # Registry-installed capabilities
|
|
@@ -188,7 +188,7 @@ app/agents/store_assistant/
|
|
|
188
188
|
├── channels/ # Slack, Teams, web, API, …
|
|
189
189
|
└── evals/ # Smoke / regression cases
|
|
190
190
|
|
|
191
|
-
app/
|
|
191
|
+
app/agents/shared/
|
|
192
192
|
├── tools/
|
|
193
193
|
├── skills/
|
|
194
194
|
├── packages/
|
|
@@ -196,7 +196,7 @@ app/agents_library/
|
|
|
196
196
|
└── connectors/
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
Keep one-off work inside the agent. Move stable capabilities to `app/
|
|
199
|
+
Keep one-off work inside the agent. Move stable capabilities to `app/agents/shared/` when another agent should reuse them, then reference via `imports.yml`. `rails-agents sync` includes imported shared files in the runtime bundle without duplicating shared source in Git.
|
|
200
200
|
|
|
201
201
|
---
|
|
202
202
|
|
data/docs/AGENTS.md
CHANGED
|
@@ -97,13 +97,13 @@ Dashboard uses `GET /agents/schema` to discover tables for database setup — ke
|
|
|
97
97
|
Add Ruby tool blocks in `agent.rb` or files under `tools/`. Tools run in your Rails app context.
|
|
98
98
|
Start with one read-only tool and test it before adding side effects.
|
|
99
99
|
|
|
100
|
-
### Workspace
|
|
100
|
+
### Workspace shared folder (reuse only when needed)
|
|
101
101
|
|
|
102
102
|
Agent-specific capabilities stay under `app/agents/<slug>/`. Capabilities used
|
|
103
103
|
by multiple agents have one canonical source under:
|
|
104
104
|
|
|
105
105
|
```text
|
|
106
|
-
app/
|
|
106
|
+
app/agents/shared/
|
|
107
107
|
├── tools/
|
|
108
108
|
├── skills/
|
|
109
109
|
├── packages/
|
|
@@ -118,20 +118,23 @@ version: 1
|
|
|
118
118
|
imports:
|
|
119
119
|
- kind: skill
|
|
120
120
|
slug: triage
|
|
121
|
-
from:
|
|
121
|
+
from: shared/skills/triage.rb
|
|
122
122
|
- kind: knowledge
|
|
123
123
|
slug: shipping_policy
|
|
124
|
-
from:
|
|
124
|
+
from: shared/knowledge/shipping_policy.md
|
|
125
125
|
- kind: package
|
|
126
126
|
slug: frontend_design
|
|
127
|
-
from:
|
|
127
|
+
from: shared/packages/frontend_design
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
`bundle exec rails-agents sync NAME` safely resolves these paths and includes
|
|
131
131
|
them in the agent bundle. It fails on path traversal, missing sources, or a
|
|
132
|
-
conflict with an agent-local file. This keeps
|
|
132
|
+
conflict with an agent-local file. This keeps shared sources canonical without
|
|
133
133
|
duplicating generated copies in Git.
|
|
134
134
|
|
|
135
|
+
Legacy installs may still use `app/agents_library/` and `from: library/...`;
|
|
136
|
+
both continue to resolve.
|
|
137
|
+
|
|
135
138
|
Shared Ruby tool files are organization boundaries, not a new DSL. Register the
|
|
136
139
|
tool in `agent.rb` using the normal `tool` block and call the shared module or
|
|
137
140
|
service from that block.
|
|
@@ -8,6 +8,8 @@ module RailsAgents
|
|
|
8
8
|
class AgentGenerator < Rails::Generators::NamedBase
|
|
9
9
|
source_root File.expand_path("templates", __dir__)
|
|
10
10
|
|
|
11
|
+
RESERVED_SLUGS = %w[shared library].freeze
|
|
12
|
+
|
|
11
13
|
class_option :type,
|
|
12
14
|
type: :string,
|
|
13
15
|
default: "knowledge",
|
|
@@ -21,6 +23,11 @@ module RailsAgents
|
|
|
21
23
|
desc "Scaffold an agent directory under app/agents/"
|
|
22
24
|
|
|
23
25
|
def create_agent_directory
|
|
26
|
+
if RESERVED_SLUGS.include?(file_name)
|
|
27
|
+
raise Thor::Error,
|
|
28
|
+
"Agent name #{file_name.inspect} is reserved for app/agents/shared/. Choose another name."
|
|
29
|
+
end
|
|
30
|
+
|
|
24
31
|
empty_directory agent_path
|
|
25
32
|
empty_directory File.join(agent_path, "tools")
|
|
26
33
|
empty_directory File.join(agent_path, "skills")
|
|
@@ -5,38 +5,14 @@ class <%= class_name %> < RailsAgents::KnowledgeAgent
|
|
|
5
5
|
memory :conversation
|
|
6
6
|
knowledge_from "knowledge/**/*"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
customer_email: order.customer_email,
|
|
17
|
-
total_cents: order.total_cents,
|
|
18
|
-
currency: order.currency,
|
|
19
|
-
shipped_at: order.shipped_at&.iso8601
|
|
20
|
-
}
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
tool :search_products do |query:|
|
|
24
|
-
scope = Product.where(status: "active")
|
|
25
|
-
if query.present?
|
|
26
|
-
pattern = "%#{query}%"
|
|
27
|
-
scope = scope.where("name LIKE ? OR sku LIKE ?", pattern, pattern)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
scope.limit(10).map do |product|
|
|
31
|
-
{
|
|
32
|
-
sku: product.sku,
|
|
33
|
-
name: product.name,
|
|
34
|
-
price_cents: product.price_cents,
|
|
35
|
-
stock: product.stock,
|
|
36
|
-
collection: product.collection&.name
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
end
|
|
8
|
+
# Add tools when the workflow needs live Rails data, e.g.:
|
|
9
|
+
# tool :lookup_order do |order_number:|
|
|
10
|
+
# order = Order.find_by(number: order_number)
|
|
11
|
+
# ...
|
|
12
|
+
# end
|
|
13
|
+
# tool :search_products do |query:|
|
|
14
|
+
# Product.where(status: "active").limit(10)...
|
|
15
|
+
# end
|
|
40
16
|
|
|
41
17
|
channel :web
|
|
42
18
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
version: 1
|
|
2
2
|
|
|
3
|
-
# Reuse capabilities from app/
|
|
3
|
+
# Reuse capabilities from app/agents/shared without duplicating source files.
|
|
4
4
|
# Example:
|
|
5
5
|
# imports:
|
|
6
6
|
# - kind: skill
|
|
7
7
|
# slug: triage
|
|
8
|
-
# from:
|
|
8
|
+
# from: shared/skills/triage.rb
|
|
9
9
|
imports: []
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Customer Support Agent
|
|
2
|
+
You are a customer support agent that answers customer questions using customer information from the database.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
## Trigger - When the agent is invoked?
|
|
5
|
+
When a customer asks a question, we will invoke this agent to understand what they are asking and respond to it.
|
|
4
6
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
## Workflow - What the agent executes?
|
|
8
|
+
1. The agent will understand the question
|
|
9
|
+
2. Ask followup questions if anything unclear
|
|
10
|
+
3. If clear, it will go and search in the database and give an answer
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## Tools
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
Add Rails tools under Tools when you need live lookups (for example `lookup_order` or `search_products`). Until a tool is written, the agent should say so instead of inventing data.
|
|
13
15
|
|
|
14
16
|
Provider credentials live in Rails Agent Cloud (BYOK). Do not commit secrets to this repository.
|
|
@@ -22,12 +22,13 @@ module RailsAgents
|
|
|
22
22
|
template "AGENTS.md.tt", "AGENTS.md"
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def
|
|
25
|
+
def create_agents_tree
|
|
26
|
+
empty_directory "app/agents"
|
|
26
27
|
%w[tools skills connectors plugins knowledge knowledge/sources packages].each do |folder|
|
|
27
|
-
empty_directory File.join("app/
|
|
28
|
+
empty_directory File.join("app/agents/shared", folder)
|
|
28
29
|
end
|
|
29
|
-
template "library_manifest.yml.tt", "app/
|
|
30
|
-
template "library_README.md.tt", "app/
|
|
30
|
+
template "library_manifest.yml.tt", "app/agents/shared/manifest.yml"
|
|
31
|
+
template "library_README.md.tt", "app/agents/shared/README.md"
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
def create_env_placeholders
|
|
@@ -31,10 +31,10 @@ Never commit provider API keys to this repository.
|
|
|
31
31
|
## Reusable capabilities
|
|
32
32
|
|
|
33
33
|
Keep agent-specific files under `app/agents/<slug>/`. Put stable tools, skills,
|
|
34
|
-
knowledge, or
|
|
35
|
-
`app/
|
|
34
|
+
knowledge, or connector manifests needed by multiple agents under
|
|
35
|
+
`app/agents/shared/`, then attach them through the agent's `imports.yml`.
|
|
36
36
|
|
|
37
|
-
Do not move a capability into
|
|
37
|
+
Do not move a capability into shared until another agent needs it.
|
|
38
38
|
|
|
39
39
|
## Taxonomy
|
|
40
40
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Shared agent capabilities
|
|
2
2
|
|
|
3
|
-
Reusable
|
|
3
|
+
Reusable tools, skills, packages, knowledge, and connectors used by more than
|
|
4
|
+
one agent in this Rails app.
|
|
4
5
|
|
|
5
6
|
- `tools/` — Ruby actions and service wrappers
|
|
6
7
|
- `skills/` — reusable multi-step behavior
|
|
@@ -18,11 +19,14 @@ version: 1
|
|
|
18
19
|
imports:
|
|
19
20
|
- kind: skill
|
|
20
21
|
slug: triage
|
|
21
|
-
from:
|
|
22
|
+
from: shared/skills/triage.rb
|
|
22
23
|
- kind: package
|
|
23
24
|
slug: frontend_design
|
|
24
|
-
from:
|
|
25
|
+
from: shared/packages/frontend_design
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
Legacy `from: library/...` paths still resolve to this folder (or to
|
|
29
|
+
`app/agents_library/` on older installs).
|
|
30
|
+
|
|
27
31
|
`rails-agents sync <agent>` uploads imported files into that agent's runtime
|
|
28
32
|
bundle without duplicating the shared source in the repository.
|
|
@@ -7,7 +7,9 @@ Rails.application.configure do
|
|
|
7
7
|
config.before_configuration do
|
|
8
8
|
if defined?(Rails.autoloaders) && Rails.autoloaders.respond_to?(:main) && Rails.autoloaders.main
|
|
9
9
|
Rails.autoloaders.main.ignore(Rails.root.join("app/agents"))
|
|
10
|
-
|
|
10
|
+
# Legacy sibling path — still ignore if an older install kept it.
|
|
11
|
+
legacy = Rails.root.join("app/agents_library")
|
|
12
|
+
Rails.autoloaders.main.ignore(legacy) if legacy.exist?
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
end
|
data/lib/rails_agents/cli.rb
CHANGED
|
@@ -108,7 +108,7 @@ module RailsAgents
|
|
|
108
108
|
)
|
|
109
109
|
|
|
110
110
|
Client.new.sync_files(agent: name, files: files)
|
|
111
|
-
suffix = imported.empty? ? "" : " (#{imported.size} from app/
|
|
111
|
+
suffix = imported.empty? ? "" : " (#{imported.size} from app/agents/shared)"
|
|
112
112
|
say "Synced #{files.size} files for #{name}#{suffix}"
|
|
113
113
|
rescue LibraryImports::Error => e
|
|
114
114
|
say_error e.message
|
|
@@ -5,8 +5,9 @@ require "yaml"
|
|
|
5
5
|
|
|
6
6
|
module RailsAgents
|
|
7
7
|
# Resolves workspace-shared capabilities declared by an agent's imports.yml.
|
|
8
|
-
# Sources live under app/
|
|
9
|
-
# copies so the cloud runtime keeps its
|
|
8
|
+
# Sources live under app/agents/shared (preferred) or legacy app/agents_library.
|
|
9
|
+
# Sync uploads virtual agent-local copies so the cloud runtime keeps its
|
|
10
|
+
# existing app/agents/<slug>/ contract.
|
|
10
11
|
class LibraryImports
|
|
11
12
|
class Error < StandardError; end
|
|
12
13
|
|
|
@@ -21,6 +22,9 @@ module RailsAgents
|
|
|
21
22
|
"knowledge" => ".md",
|
|
22
23
|
"package" => ".yml"
|
|
23
24
|
}.freeze
|
|
25
|
+
# Logical import prefixes → physical shared root (app/agents/shared).
|
|
26
|
+
# "library/" kept for backwards-compatible imports.yml files.
|
|
27
|
+
FROM_PREFIXES = %w[shared/ library/].freeze
|
|
24
28
|
|
|
25
29
|
attr_reader :agent_directory, :library_root
|
|
26
30
|
|
|
@@ -43,12 +47,12 @@ module RailsAgents
|
|
|
43
47
|
|
|
44
48
|
def virtual_files
|
|
45
49
|
entries.flat_map do |entry|
|
|
46
|
-
raise Error, "Missing
|
|
50
|
+
raise Error, "Missing shared source: #{entry.source}" unless entry.source.exist?
|
|
47
51
|
|
|
48
52
|
if entry.kind == "package"
|
|
49
53
|
package_virtual_files(entry)
|
|
50
54
|
else
|
|
51
|
-
raise Error, "Missing
|
|
55
|
+
raise Error, "Missing shared source: #{entry.source}" unless entry.source.file?
|
|
52
56
|
|
|
53
57
|
[{
|
|
54
58
|
"path" => cloud_path(entry.target),
|
|
@@ -63,6 +67,17 @@ module RailsAgents
|
|
|
63
67
|
entries.select { |entry| entry.kind == "knowledge" }.map { |entry| entry.target.to_s }
|
|
64
68
|
end
|
|
65
69
|
|
|
70
|
+
def self.resolve_library_root(agents_root)
|
|
71
|
+
agents_root = Pathname.new(agents_root)
|
|
72
|
+
shared = agents_root.join("shared")
|
|
73
|
+
return shared if shared.exist?
|
|
74
|
+
|
|
75
|
+
legacy = agents_root.parent.join("agents_library")
|
|
76
|
+
return legacy if legacy.exist?
|
|
77
|
+
|
|
78
|
+
shared
|
|
79
|
+
end
|
|
80
|
+
|
|
66
81
|
private
|
|
67
82
|
|
|
68
83
|
def package_virtual_files(entry)
|
|
@@ -74,7 +89,7 @@ module RailsAgents
|
|
|
74
89
|
else
|
|
75
90
|
entry.source
|
|
76
91
|
end
|
|
77
|
-
raise Error, "Missing
|
|
92
|
+
raise Error, "Missing shared package directory: #{root}" unless root.directory?
|
|
78
93
|
|
|
79
94
|
Dir.glob(root.join("**", "*").to_s).select { |path| File.file?(path) }.map do |path|
|
|
80
95
|
file = Pathname.new(path)
|
|
@@ -93,7 +108,7 @@ module RailsAgents
|
|
|
93
108
|
end
|
|
94
109
|
|
|
95
110
|
def default_library_root
|
|
96
|
-
agent_directory.parent
|
|
111
|
+
self.class.resolve_library_root(agent_directory.parent)
|
|
97
112
|
end
|
|
98
113
|
|
|
99
114
|
def build_entry(raw)
|
|
@@ -102,12 +117,15 @@ module RailsAgents
|
|
|
102
117
|
kind = raw["kind"].to_s
|
|
103
118
|
kind = "connector" if kind == "plugin"
|
|
104
119
|
slug = normalize_slug(raw["slug"])
|
|
105
|
-
raise Error, "Unsupported
|
|
106
|
-
raise Error, "
|
|
120
|
+
raise Error, "Unsupported shared kind: #{kind.inspect}" unless KINDS.include?(kind)
|
|
121
|
+
raise Error, "Shared import slug is required" if slug.empty?
|
|
107
122
|
|
|
108
123
|
from = raw["from"].to_s
|
|
109
|
-
prefix =
|
|
110
|
-
|
|
124
|
+
prefix = FROM_PREFIXES.find { |p| from.start_with?(p) }
|
|
125
|
+
unless prefix
|
|
126
|
+
raise Error,
|
|
127
|
+
"Shared import #{slug} must use from: shared/... (or legacy library/...)"
|
|
128
|
+
end
|
|
111
129
|
|
|
112
130
|
source_relative = safe_relative(from.delete_prefix(prefix), "source")
|
|
113
131
|
source = library_root.join(source_relative)
|
|
@@ -131,7 +149,7 @@ module RailsAgents
|
|
|
131
149
|
path = Pathname.new(value)
|
|
132
150
|
clean = path.cleanpath
|
|
133
151
|
if path.absolute? || clean.to_s == ".." || clean.to_s.start_with?("../")
|
|
134
|
-
raise Error, "
|
|
152
|
+
raise Error, "Shared import #{label} must stay inside its root"
|
|
135
153
|
end
|
|
136
154
|
clean
|
|
137
155
|
end
|
data/lib/rails_agents/version.rb
CHANGED
data/rails-agent-stack.gemspec
CHANGED
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.description = <<~DESC
|
|
15
15
|
Rails Agent is a single, beautiful full-stack agentic platform for Ruby on Rails. Build chatbots, knowledge (RAG-style) agents, workflow agents, operations jobs, monitoring agents, and every agentic workflow you can think of — as files in app/agents/, with a mounted /agents dashboard and hosted cloud runtime.
|
|
16
16
|
|
|
17
|
-
Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and
|
|
17
|
+
Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and app/agents/shared for reusable capabilities.
|
|
18
18
|
|
|
19
19
|
Test: cloud sandbox runs, streaming, evals (golden cases), traces, and cost before you ship.
|
|
20
20
|
|
|
@@ -12,18 +12,19 @@ RSpec.describe "Agent generator templates" do
|
|
|
12
12
|
expect(content).not_to include("model :auto")
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
it "database template scaffolds KnowledgeAgent
|
|
16
|
-
content = File.read(File.join(templates_root, "agent_database.rb.tt"))
|
|
15
|
+
it "database template scaffolds KnowledgeAgent without binding default tools" do
|
|
16
|
+
content = File.read(File.join(templates_root, "agent_database.rb.tt"), encoding: "UTF-8")
|
|
17
17
|
expect(content).to include("KnowledgeAgent")
|
|
18
|
-
expect(content).to include("
|
|
19
|
-
expect(content).
|
|
20
|
-
expect(content).
|
|
21
|
-
expect(content).to include("Product.where")
|
|
18
|
+
expect(content).to include("Add tools when the workflow needs live Rails data")
|
|
19
|
+
expect(content).not_to match(/^\s*tool :lookup_order/m)
|
|
20
|
+
expect(content).not_to match(/^\s*tool :search_products/m)
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
it "database prompt documents
|
|
23
|
+
it "database prompt documents support triage workflow and BYOK" do
|
|
25
24
|
content = File.read(File.join(templates_root, "prompt_database.md.tt"))
|
|
26
|
-
expect(content).to include("
|
|
25
|
+
expect(content).to include("Customer Support Agent")
|
|
26
|
+
expect(content).to include("Ask followup questions if anything unclear")
|
|
27
|
+
expect(content).to include("Until a tool is written")
|
|
27
28
|
expect(content).to include("BYOK")
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -31,6 +32,6 @@ RSpec.describe "Agent generator templates" do
|
|
|
31
32
|
content = File.read(File.join(templates_root, "imports.yml.tt"))
|
|
32
33
|
|
|
33
34
|
expect(content).to include("imports: []")
|
|
34
|
-
expect(content).to include("
|
|
35
|
+
expect(content).to include("shared/skills/triage.rb")
|
|
35
36
|
end
|
|
36
37
|
end
|
|
@@ -9,22 +9,22 @@ RSpec.describe RailsAgents::LibraryImports do
|
|
|
9
9
|
Dir.mktmpdir do |root|
|
|
10
10
|
@root = Pathname.new(root)
|
|
11
11
|
@agent_dir = @root.join("app/agents/support")
|
|
12
|
-
@
|
|
12
|
+
@shared_dir = @root.join("app/agents/shared")
|
|
13
13
|
FileUtils.mkdir_p(@agent_dir)
|
|
14
|
-
FileUtils.mkdir_p(@
|
|
14
|
+
FileUtils.mkdir_p(@shared_dir)
|
|
15
15
|
example.run
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it "builds virtual agent files from shared
|
|
20
|
-
FileUtils.mkdir_p(@
|
|
21
|
-
@
|
|
19
|
+
it "builds virtual agent files from app/agents/shared imports" do
|
|
20
|
+
FileUtils.mkdir_p(@shared_dir.join("skills"))
|
|
21
|
+
@shared_dir.join("skills/triage.rb").write("module Triage; end\n")
|
|
22
22
|
@agent_dir.join("imports.yml").write(<<~YAML)
|
|
23
23
|
version: 1
|
|
24
24
|
imports:
|
|
25
25
|
- kind: skill
|
|
26
26
|
slug: triage
|
|
27
|
-
from:
|
|
27
|
+
from: shared/skills/triage.rb
|
|
28
28
|
YAML
|
|
29
29
|
|
|
30
30
|
files = described_class.new(@agent_dir).virtual_files
|
|
@@ -38,15 +38,33 @@ RSpec.describe RailsAgents::LibraryImports do
|
|
|
38
38
|
)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
it "still resolves legacy from: library/ and app/agents_library/" do
|
|
42
|
+
legacy = @root.join("app/agents_library")
|
|
43
|
+
FileUtils.rm_rf(@shared_dir)
|
|
44
|
+
FileUtils.mkdir_p(legacy.join("skills"))
|
|
45
|
+
legacy.join("skills/triage.rb").write("module Triage; end\n")
|
|
46
|
+
@agent_dir.join("imports.yml").write(<<~YAML)
|
|
47
|
+
version: 1
|
|
48
|
+
imports:
|
|
49
|
+
- kind: skill
|
|
50
|
+
slug: triage
|
|
51
|
+
from: library/skills/triage.rb
|
|
52
|
+
YAML
|
|
53
|
+
|
|
54
|
+
files = described_class.new(@agent_dir).virtual_files
|
|
55
|
+
|
|
56
|
+
expect(files.first["path"]).to eq("app/agents/support/skills/triage.rb")
|
|
57
|
+
end
|
|
58
|
+
|
|
41
59
|
it "exposes imported knowledge at its agent-relative runtime path" do
|
|
42
|
-
FileUtils.mkdir_p(@
|
|
43
|
-
@
|
|
60
|
+
FileUtils.mkdir_p(@shared_dir.join("knowledge"))
|
|
61
|
+
@shared_dir.join("knowledge/policy.md").write("# Policy\n")
|
|
44
62
|
@agent_dir.join("imports.yml").write(<<~YAML)
|
|
45
63
|
version: 1
|
|
46
64
|
imports:
|
|
47
65
|
- kind: knowledge
|
|
48
66
|
slug: policy
|
|
49
|
-
from:
|
|
67
|
+
from: shared/knowledge/policy.md
|
|
50
68
|
as: knowledge/company/policy.md
|
|
51
69
|
YAML
|
|
52
70
|
|
|
@@ -58,13 +76,13 @@ RSpec.describe RailsAgents::LibraryImports do
|
|
|
58
76
|
)
|
|
59
77
|
end
|
|
60
78
|
|
|
61
|
-
it "rejects paths that escape the
|
|
79
|
+
it "rejects paths that escape the shared root" do
|
|
62
80
|
@agent_dir.join("imports.yml").write(<<~YAML)
|
|
63
81
|
version: 1
|
|
64
82
|
imports:
|
|
65
83
|
- kind: tool
|
|
66
84
|
slug: secret
|
|
67
|
-
from:
|
|
85
|
+
from: shared/../../config/master.key
|
|
68
86
|
YAML
|
|
69
87
|
|
|
70
88
|
expect { described_class.new(@agent_dir).entries }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-agent-stack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tiny Bubble Company
|
|
@@ -97,7 +97,7 @@ dependencies:
|
|
|
97
97
|
description: |
|
|
98
98
|
Rails Agent is a single, beautiful full-stack agentic platform for Ruby on Rails. Build chatbots, knowledge (RAG-style) agents, workflow agents, operations jobs, monitoring agents, and every agentic workflow you can think of — as files in app/agents/, with a mounted /agents dashboard and hosted cloud runtime.
|
|
99
99
|
|
|
100
|
-
Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and
|
|
100
|
+
Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and app/agents/shared for reusable capabilities.
|
|
101
101
|
|
|
102
102
|
Test: cloud sandbox runs, streaming, evals (golden cases), traces, and cost before you ship.
|
|
103
103
|
|