action_ai 0.1.0 → 0.2.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/CHANGELOG.md +11 -0
- data/README.rdoc +25 -1
- data/lib/action_ai/agent.rb +1 -0
- data/lib/action_ai/implicit_interaction.rb +19 -0
- data/lib/action_ai/interaction.rb +17 -0
- data/lib/action_ai/version.rb +1 -1
- data/lib/action_ai.rb +1 -0
- data/lib/ruby_llm/providers/test/echo.rb +4 -1
- metadata +159 -143
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f5b0c31e7ae5b9944a95f32563d3873adea7134ea32e11ebfc5dbc2a81eafec9
|
|
4
|
+
data.tar.gz: d20750877288e1e1306a58a08f6b1aeea02985d749df8ce763262e0cc68314e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84b92d55d7310f17e3746457cd76ecdae5dbed20aee80276b61d30824b38093d13c3f4753b69925e819dac9471bcfd5d1c1733aa46c78dd68969d0350c24a0c7
|
|
7
|
+
data.tar.gz: 0bbec9e620ec3fa03151b8dc4d6223b8a1de5d6b18cb4731c96df73d1bd2a9fb25a862c4dc3cbe27093468376a61c90d32f6763ef95f88f9c2f78118a077934e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.0] - 2026-06-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Implicit `ask` behavior for AI actions without explicit prompts, matching Action Controller-style ergonomics.
|
|
10
|
+
- Action chaining, enabling users to construct complex AI workflows from discrete jobs.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `echo` test model to support multiple chat interactions.
|
|
15
|
+
|
|
5
16
|
## [0.1.0] - 2026-05-05
|
|
6
17
|
|
|
7
18
|
Refactored from Action Mailer.
|
data/README.rdoc
CHANGED
|
@@ -16,6 +16,8 @@ shape for AI interactions rather than building an unrelated API from scratch.
|
|
|
16
16
|
|
|
17
17
|
The framework works by initializing any instance variables you want to be
|
|
18
18
|
available in the prompt template.
|
|
19
|
+
Like +render+ in Action Controller, the implicit +ask+ will be triggered
|
|
20
|
+
automatically at the end of the action unless you have already called it.
|
|
19
21
|
|
|
20
22
|
This can be as simple as:
|
|
21
23
|
|
|
@@ -25,10 +27,16 @@ This can be as simple as:
|
|
|
25
27
|
def code(task, language)
|
|
26
28
|
@task = task
|
|
27
29
|
@language = language
|
|
28
|
-
ask
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
If you need to customize the prompt execution (e.g., pass options or a custom prompt),
|
|
34
|
+
you can call +ask+ explicitly:
|
|
35
|
+
|
|
36
|
+
def run(spec_file)
|
|
37
|
+
ask "Run the attached spec", with: spec_file
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
After the action method completes, the framework will automatically:
|
|
33
41
|
1. Render the prompt from the corresponding template (e.g., +app/ai/prompts/generator/code.erb+)
|
|
34
42
|
2. Send it to the configured AI model via +ask+
|
|
@@ -64,6 +72,22 @@ Or you can just chain the methods together like:
|
|
|
64
72
|
|
|
65
73
|
Generator.code("Parse CSV and dedupe", :ruby).content # Returns AI's response for the prompt
|
|
66
74
|
|
|
75
|
+
You can also chain multiple agent actions to compose a small workflow before reading the final response:
|
|
76
|
+
|
|
77
|
+
class WorkflowAgent < ApplicationAI
|
|
78
|
+
def collect(topic)
|
|
79
|
+
@topic = topic
|
|
80
|
+
ask "Collect #{@topic}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def refine(style:)
|
|
84
|
+
ask "Refine #{@topic} as #{style}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
WorkflowAgent.collect("release notes").refine(style: "bullet list").content
|
|
89
|
+
# => collected release notes refined as bullet list
|
|
90
|
+
|
|
67
91
|
== Setting defaults
|
|
68
92
|
|
|
69
93
|
It is possible to set default values that will be used in every method in your
|
data/lib/action_ai/agent.rb
CHANGED
|
@@ -278,6 +278,7 @@ module ActionAI
|
|
|
278
278
|
# <tt>execution_job</tt>. Agents can set this to use a custom queue name.
|
|
279
279
|
class Agent < AbstractController::Base
|
|
280
280
|
include Callbacks
|
|
281
|
+
include ImplicitInteraction
|
|
281
282
|
include QueuedExecution
|
|
282
283
|
include Rescuable
|
|
283
284
|
include Parameterized
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionAI
|
|
4
|
+
# # Action AI Implicit Interaction
|
|
5
|
+
#
|
|
6
|
+
# Handles implicit interactions for an agent action that does not explicitly
|
|
7
|
+
# respond with `ask`.
|
|
8
|
+
#
|
|
9
|
+
# If no explicit `ask` is performed by the action, the implicit response is
|
|
10
|
+
# to call `ask` with the default prompt rendering.
|
|
11
|
+
module ImplicitInteraction
|
|
12
|
+
def send_action(...)
|
|
13
|
+
super
|
|
14
|
+
.tap { default_interaction unless performed? }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def default_interaction = ask
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -77,6 +77,23 @@ module ActionAI
|
|
|
77
77
|
# end
|
|
78
78
|
def later(...) = enqueue_execution(...)
|
|
79
79
|
|
|
80
|
+
ruby2_keywords def method_missing(method, *args, &)
|
|
81
|
+
case method.name
|
|
82
|
+
when *@agent_class.action_methods
|
|
83
|
+
processed_agent.process(@action = method, *(@args = args), &)
|
|
84
|
+
self
|
|
85
|
+
else
|
|
86
|
+
super
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def respond_to_missing?(method, include_private = false)
|
|
91
|
+
[
|
|
92
|
+
method.name.in?(@agent_class.action_methods),
|
|
93
|
+
super,
|
|
94
|
+
].any?
|
|
95
|
+
end
|
|
96
|
+
|
|
80
97
|
private
|
|
81
98
|
# Returns the processed Agent instance. We keep this instance
|
|
82
99
|
# on hand so we can run callbacks and delegate exception handling to it.
|
data/lib/action_ai/version.rb
CHANGED
data/lib/action_ai.rb
CHANGED
|
@@ -26,7 +26,10 @@ module RubyLLM
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
28
|
def echo_response(messages, **) = {
|
|
29
|
-
content: RubyLLM.concat_content(messages
|
|
29
|
+
content: RubyLLM.concat_content(messages
|
|
30
|
+
.reverse_each.take_while { it.role != :assistant }.reverse
|
|
31
|
+
.map(&:content)
|
|
32
|
+
),
|
|
30
33
|
}
|
|
31
34
|
end
|
|
32
35
|
end
|
metadata
CHANGED
|
@@ -1,169 +1,185 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: action_ai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Alexander Senko
|
|
7
|
+
- Alexander Senko
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
-
- !ruby/object:Gem::Dependency
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- !ruby/object:Gem::
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
- !ruby/object:Gem::
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
-
|
|
17
|
+
- ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: "0"
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
-
|
|
25
|
+
- ">="
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: "0"
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: actionpack
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
-
|
|
33
|
+
- ">="
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: "0"
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
-
|
|
41
|
+
- ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: "0"
|
|
44
|
+
- !ruby/object:Gem::Dependency
|
|
45
|
+
name: actionview
|
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
-
|
|
49
|
+
- ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: "0"
|
|
52
|
+
type: :runtime
|
|
53
|
+
prerelease: false
|
|
54
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
-
|
|
57
|
+
- ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: "0"
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: activejob
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
-
|
|
65
|
+
- ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: "0"
|
|
68
|
+
type: :runtime
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
-
|
|
73
|
+
- ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: "0"
|
|
76
|
+
- !ruby/object:Gem::Dependency
|
|
77
|
+
name: ruby_llm
|
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
-
|
|
81
|
+
- ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: "0"
|
|
84
|
+
type: :runtime
|
|
85
|
+
prerelease: false
|
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
-
|
|
89
|
+
- ">="
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: "0"
|
|
92
|
+
- !ruby/object:Gem::Dependency
|
|
93
|
+
name: memery
|
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
-
|
|
97
|
+
- ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: "0"
|
|
100
|
+
type: :runtime
|
|
101
|
+
prerelease: false
|
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
-
|
|
105
|
+
- ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: "0"
|
|
108
|
+
- !ruby/object:Gem::Dependency
|
|
109
|
+
name: rails-dom-testing
|
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
|
111
|
+
requirements:
|
|
112
|
+
-
|
|
113
|
+
- ~>
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: "2.2"
|
|
116
|
+
type: :runtime
|
|
117
|
+
prerelease: false
|
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
-
|
|
121
|
+
- ~>
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: "2.2"
|
|
124
|
+
description: "AI on Rails. Compose, run, and test AI prompts using the familiar controller/view pattern."
|
|
112
125
|
email: Alexander.Senko@gmail.com
|
|
113
126
|
executables: []
|
|
114
127
|
extensions: []
|
|
115
128
|
extra_rdoc_files: []
|
|
116
129
|
files:
|
|
117
|
-
- CHANGELOG.md
|
|
118
|
-
- MIT-LICENSE
|
|
119
|
-
- README.rdoc
|
|
120
|
-
- lib/action_ai.rb
|
|
121
|
-
- lib/action_ai/agent.rb
|
|
122
|
-
- lib/action_ai/callbacks.rb
|
|
123
|
-
- lib/action_ai/deprecator.rb
|
|
124
|
-
- lib/action_ai/execution_job.rb
|
|
125
|
-
- lib/action_ai/
|
|
126
|
-
- lib/action_ai/
|
|
127
|
-
- lib/action_ai/
|
|
128
|
-
- lib/action_ai/
|
|
129
|
-
- lib/action_ai/
|
|
130
|
-
- lib/action_ai/
|
|
131
|
-
- lib/action_ai/
|
|
132
|
-
- lib/action_ai/
|
|
133
|
-
- lib/action_ai/
|
|
134
|
-
- lib/action_ai/
|
|
135
|
-
- lib/action_ai/
|
|
136
|
-
- lib/
|
|
137
|
-
- lib/rails/generators/ai/
|
|
138
|
-
- lib/rails/generators/ai/
|
|
139
|
-
- lib/rails/generators/ai/templates/
|
|
140
|
-
- lib/
|
|
141
|
-
- lib/ruby_llm/providers/test
|
|
142
|
-
- lib/ruby_llm/
|
|
143
|
-
|
|
130
|
+
- CHANGELOG.md
|
|
131
|
+
- MIT-LICENSE
|
|
132
|
+
- README.rdoc
|
|
133
|
+
- lib/action_ai.rb
|
|
134
|
+
- lib/action_ai/agent.rb
|
|
135
|
+
- lib/action_ai/callbacks.rb
|
|
136
|
+
- lib/action_ai/deprecator.rb
|
|
137
|
+
- lib/action_ai/execution_job.rb
|
|
138
|
+
- lib/action_ai/implicit_interaction.rb
|
|
139
|
+
- lib/action_ai/interaction.rb
|
|
140
|
+
- lib/action_ai/log_subscriber.rb
|
|
141
|
+
- lib/action_ai/parameterized.rb
|
|
142
|
+
- lib/action_ai/preview.rb
|
|
143
|
+
- lib/action_ai/prompt_helper.rb
|
|
144
|
+
- lib/action_ai/queued_execution.rb
|
|
145
|
+
- lib/action_ai/railtie.rb
|
|
146
|
+
- lib/action_ai/rescuable.rb
|
|
147
|
+
- lib/action_ai/test_case.rb
|
|
148
|
+
- lib/action_ai/test_helper.rb
|
|
149
|
+
- lib/action_ai/version.rb
|
|
150
|
+
- lib/rails/generators/ai/USAGE
|
|
151
|
+
- lib/rails/generators/ai/ai_generator.rb
|
|
152
|
+
- lib/rails/generators/ai/templates/agent.rb.tt
|
|
153
|
+
- lib/rails/generators/ai/templates/application_agent.rb.tt
|
|
154
|
+
- lib/ruby_llm/providers/test.rb
|
|
155
|
+
- lib/ruby_llm/providers/test/echo.rb
|
|
156
|
+
- lib/ruby_llm/tester.rb
|
|
157
|
+
homepage: "https://github.com/Alexander-Senko/action_ai"
|
|
144
158
|
licenses:
|
|
145
|
-
- MIT
|
|
159
|
+
- MIT
|
|
146
160
|
metadata:
|
|
147
|
-
bug_tracker_uri: https://github.com/Alexander-Senko/action_ai/issues
|
|
148
|
-
changelog_uri: https://github.com/Alexander-Senko/action_ai/blob/v0.
|
|
149
|
-
source_code_uri: https://github.com/Alexander-Senko/action_ai/tree/v0.
|
|
150
|
-
rubygems_mfa_required:
|
|
161
|
+
bug_tracker_uri: "https://github.com/Alexander-Senko/action_ai/issues"
|
|
162
|
+
changelog_uri: "https://github.com/Alexander-Senko/action_ai/blob/v0.2.0/CHANGELOG.md"
|
|
163
|
+
source_code_uri: "https://github.com/Alexander-Senko/action_ai/tree/v0.2.0"
|
|
164
|
+
rubygems_mfa_required: "true"
|
|
151
165
|
rdoc_options: []
|
|
152
166
|
require_paths:
|
|
153
|
-
- lib
|
|
167
|
+
- lib
|
|
154
168
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
169
|
requirements:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
170
|
+
-
|
|
171
|
+
- ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: "3.4"
|
|
159
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
175
|
requirements:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
176
|
+
-
|
|
177
|
+
- ">="
|
|
178
|
+
- !ruby/object:Gem::Version
|
|
179
|
+
version: "0"
|
|
164
180
|
requirements:
|
|
165
|
-
- none
|
|
166
|
-
rubygems_version:
|
|
181
|
+
- none
|
|
182
|
+
rubygems_version: 4.1.0.dev
|
|
167
183
|
specification_version: 4
|
|
168
184
|
summary: AI prompt composition and running framework
|
|
169
185
|
test_files: []
|