a2a-rails 0.1.0 → 0.2.0.rc2
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 +56 -0
- data/README.md +261 -205
- data/app/controllers/a2a/rails/agent_cards_controller.rb +3 -0
- data/app/controllers/a2a/rails/requests_controller.rb +53 -0
- data/lib/a2a/rails/agent.rb +33 -2
- data/lib/a2a/rails/agent_card/builder.rb +3 -1
- data/lib/a2a/rails/agent_card/security.rb +115 -0
- data/lib/a2a/rails/authentication.rb +71 -0
- data/lib/a2a/rails/configuration.rb +95 -1
- data/lib/a2a/rails/dispatcher.rb +36 -4
- data/lib/a2a/rails/errors.rb +3 -0
- data/lib/a2a/rails/execution_plan.rb +40 -0
- data/lib/a2a/rails/file_artifact.rb +77 -0
- data/lib/a2a/rails/protocol/agent2agent_adapter.rb +11 -0
- data/lib/a2a/rails/protocol/request_handler.rb +124 -13
- data/lib/a2a/rails/protocol/task_mapper.rb +21 -0
- data/lib/a2a/rails/request_guard.rb +76 -0
- data/lib/a2a/rails/runtime.rb +15 -6
- data/lib/a2a/rails/skill.rb +7 -2
- data/lib/a2a/rails/task/active_record_store.rb +451 -0
- data/lib/a2a/rails/task/artifact_mapper.rb +2 -0
- data/lib/a2a/rails/task/lifecycle.rb +18 -8
- data/lib/a2a/rails/task/memory_store.rb +39 -15
- data/lib/a2a/rails/task/store.rb +16 -4
- data/lib/a2a/rails/task_execution_arguments.rb +78 -0
- data/lib/a2a/rails/task_execution_job.rb +79 -0
- data/lib/a2a/rails/version.rb +1 -1
- data/lib/a2a-rails.rb +7 -0
- data/lib/generators/a2a/rails/task_store_generator.rb +46 -0
- data/lib/generators/a2a/rails/templates/create_a2a_rails_tasks.rb.tt +31 -0
- data/lib/generators/a2a/rails/templates/initializer.rb.tt +4 -0
- data/lib/tasks/a2a_rails_tasks.rake +54 -0
- metadata +94 -3
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module A2A
|
|
4
|
+
module Rails
|
|
5
|
+
class TaskExecutionArguments
|
|
6
|
+
MAX_IDENTIFIER_BYTES = 256
|
|
7
|
+
MAX_CLASS_NAME_BYTES = 512
|
|
8
|
+
KEYS = %i[task_id principal_id agent_class_name skill_id].freeze
|
|
9
|
+
|
|
10
|
+
attr_reader(*KEYS)
|
|
11
|
+
|
|
12
|
+
def initialize(task_id:, principal_id:, agent_class_name:, skill_id:)
|
|
13
|
+
@task_id = normalize_identifier(task_id, "task_id")
|
|
14
|
+
@principal_id = normalize_principal_id(principal_id)
|
|
15
|
+
@agent_class_name = normalize_agent_class_name(agent_class_name)
|
|
16
|
+
@skill_id = normalize_skill_id(skill_id)
|
|
17
|
+
@payload = {
|
|
18
|
+
task_id: @task_id,
|
|
19
|
+
principal_id: @principal_id,
|
|
20
|
+
agent_class_name: @agent_class_name,
|
|
21
|
+
skill_id: @skill_id
|
|
22
|
+
}.freeze
|
|
23
|
+
freeze
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_h
|
|
27
|
+
@payload
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def normalize_identifier(value, label)
|
|
33
|
+
unless safe_string?(value, max_bytes: MAX_IDENTIFIER_BYTES)
|
|
34
|
+
raise ConfigurationError, "#{label} must be a non-empty safe String"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
value.dup.freeze
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def normalize_principal_id(value)
|
|
41
|
+
return nil if value.nil?
|
|
42
|
+
|
|
43
|
+
unless Authentication.valid_principal_id?(value)
|
|
44
|
+
raise ConfigurationError, "principal_id must be a valid non-secret principal ID String"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
value.dup.freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def normalize_agent_class_name(value)
|
|
51
|
+
return nil if value.nil?
|
|
52
|
+
|
|
53
|
+
unless safe_string?(value, max_bytes: MAX_CLASS_NAME_BYTES)
|
|
54
|
+
raise ConfigurationError, "agent_class_name must be a safe class-name String"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
parts = value.sub(/\A::/, "").split("::")
|
|
58
|
+
unless parts.all? { |part| part.match?(/\A[A-Z]\w*\z/) }
|
|
59
|
+
raise ConfigurationError, "agent_class_name must be a valid class-name String"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
value.dup.freeze
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def normalize_skill_id(value)
|
|
66
|
+
string = value.is_a?(Symbol) ? value.to_s : value
|
|
67
|
+
normalize_identifier(string, "skill_id")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def safe_string?(value, max_bytes:)
|
|
71
|
+
value.is_a?(String) &&
|
|
72
|
+
!value.strip.empty? &&
|
|
73
|
+
value.bytesize <= max_bytes &&
|
|
74
|
+
!value.match?(/[[:cntrl:]]/)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_job"
|
|
4
|
+
|
|
5
|
+
module A2A
|
|
6
|
+
module Rails
|
|
7
|
+
class TaskExecutionJob < ::ActiveJob::Base
|
|
8
|
+
queue_as :default
|
|
9
|
+
# The Task is already persisted before enqueue. Keep the enqueue boundary
|
|
10
|
+
# immediate and independent from any surrounding host Active Record transaction.
|
|
11
|
+
self.enqueue_after_transaction_commit = false
|
|
12
|
+
|
|
13
|
+
def perform(task_id:, principal_id:, agent_class_name:, skill_id:)
|
|
14
|
+
arguments = TaskExecutionArguments.new(
|
|
15
|
+
task_id: task_id,
|
|
16
|
+
principal_id: principal_id,
|
|
17
|
+
agent_class_name: agent_class_name,
|
|
18
|
+
skill_id: skill_id
|
|
19
|
+
)
|
|
20
|
+
task_id = arguments.task_id
|
|
21
|
+
principal_id = arguments.principal_id
|
|
22
|
+
agent_class_name = arguments.agent_class_name
|
|
23
|
+
skill_id = arguments.skill_id
|
|
24
|
+
|
|
25
|
+
configuration = A2A::Rails.configuration
|
|
26
|
+
lifecycle = Task::Lifecycle.new(
|
|
27
|
+
store: A2A::Rails.runtime.task_store,
|
|
28
|
+
logger: configuration.logger,
|
|
29
|
+
principal_id: principal_id
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
claimed = lifecycle.claim_execution(task_id)
|
|
33
|
+
return unless claimed
|
|
34
|
+
|
|
35
|
+
agent = configuration.resolve_agent
|
|
36
|
+
unless agent_class_name.nil? || agent.name == agent_class_name
|
|
37
|
+
raise ConfigurationError, "Queued Agent no longer matches configured Agent"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
message = original_message(claimed)
|
|
41
|
+
plan = ExecutionPlan.new(
|
|
42
|
+
agent_class_name: agent_class_name,
|
|
43
|
+
skill_id: skill_id,
|
|
44
|
+
execution_mode: :async
|
|
45
|
+
)
|
|
46
|
+
context = {
|
|
47
|
+
task_id: task_id,
|
|
48
|
+
context_id: claimed.fetch(:context_id),
|
|
49
|
+
principal_id: principal_id,
|
|
50
|
+
idempotency_key: task_id
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
result = Dispatcher.new(agent: agent, configuration: configuration).execute(
|
|
54
|
+
plan: plan,
|
|
55
|
+
message: message,
|
|
56
|
+
context: context
|
|
57
|
+
)
|
|
58
|
+
lifecycle.complete(task_id, result)
|
|
59
|
+
rescue RejectedTask => error
|
|
60
|
+
lifecycle&.reject(task_id, error)
|
|
61
|
+
rescue TaskNotFoundError
|
|
62
|
+
nil
|
|
63
|
+
rescue StandardError => error
|
|
64
|
+
lifecycle&.fail(task_id, error) if lifecycle
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def original_message(task)
|
|
70
|
+
history = task[:history]
|
|
71
|
+
unless history.is_a?(Array) && history.first.is_a?(Hash)
|
|
72
|
+
raise ConfigurationError, "Queued Task does not contain an original Message"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
history.first
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/a2a/rails/version.rb
CHANGED
data/lib/a2a-rails.rb
CHANGED
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "a2a/rails/version"
|
|
4
4
|
require_relative "a2a/rails/errors"
|
|
5
|
+
require_relative "a2a/rails/file_artifact"
|
|
6
|
+
require_relative "a2a/rails/authentication"
|
|
7
|
+
require_relative "a2a/rails/request_guard"
|
|
5
8
|
require_relative "a2a/rails/configuration"
|
|
6
9
|
require_relative "a2a/rails/skill"
|
|
7
10
|
require_relative "a2a/rails/agent"
|
|
11
|
+
require_relative "a2a/rails/execution_plan"
|
|
8
12
|
require_relative "a2a/rails/dispatcher"
|
|
13
|
+
require_relative "a2a/rails/agent_card/security"
|
|
9
14
|
require_relative "a2a/rails/agent_card/validator"
|
|
10
15
|
require_relative "a2a/rails/agent_card/builder"
|
|
11
16
|
require_relative "a2a/rails/task"
|
|
17
|
+
require_relative "a2a/rails/task_execution_arguments"
|
|
18
|
+
require_relative "a2a/rails/task_execution_job"
|
|
12
19
|
require_relative "a2a/rails/protocol/adapter"
|
|
13
20
|
require_relative "a2a/rails/protocol/task_mapper"
|
|
14
21
|
require_relative "a2a/rails/protocol/request_handler"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "rails/generators"
|
|
5
|
+
require "rails/generators/migration"
|
|
6
|
+
require "active_record"
|
|
7
|
+
require "rails/generators/active_record"
|
|
8
|
+
rescue LoadError => error
|
|
9
|
+
raise LoadError,
|
|
10
|
+
"a2a:rails:task_store requires ActiveRecord in the host application (#{error.path})"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module A2A
|
|
14
|
+
module Rails
|
|
15
|
+
class TaskStoreGenerator < ::Rails::Generators::Base
|
|
16
|
+
include ::Rails::Generators::Migration
|
|
17
|
+
|
|
18
|
+
namespace "a2a:rails:task_store"
|
|
19
|
+
source_root File.expand_path("templates", __dir__)
|
|
20
|
+
|
|
21
|
+
def self.next_migration_number(dirname)
|
|
22
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create_task_store_migration
|
|
26
|
+
migration_template(
|
|
27
|
+
"create_a2a_rails_tasks.rb.tt",
|
|
28
|
+
"db/migrate/create_a2a_rails_tasks.rb"
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def show_configuration
|
|
33
|
+
say <<~MESSAGE
|
|
34
|
+
|
|
35
|
+
Configure the durable store in config/initializers/a2a_rails.rb:
|
|
36
|
+
|
|
37
|
+
config.task_store = :active_record
|
|
38
|
+
|
|
39
|
+
Then run:
|
|
40
|
+
|
|
41
|
+
bin/rails db:migrate
|
|
42
|
+
MESSAGE
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class CreateA2aRailsTasks < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :a2a_rails_tasks do |t|
|
|
4
|
+
t.string :task_id, null: false
|
|
5
|
+
t.string :owner_id
|
|
6
|
+
t.string :context_id, null: false
|
|
7
|
+
t.string :state, null: false
|
|
8
|
+
t.datetime :status_timestamp, precision: 6, null: false
|
|
9
|
+
t.json :status_message
|
|
10
|
+
t.json :history
|
|
11
|
+
t.json :artifacts
|
|
12
|
+
t.datetime :expires_at, precision: 6
|
|
13
|
+
|
|
14
|
+
t.timestamps
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
add_index :a2a_rails_tasks, :task_id,
|
|
18
|
+
unique: true,
|
|
19
|
+
name: "idx_a2a_tasks_task_id"
|
|
20
|
+
add_index :a2a_rails_tasks, [:owner_id, :task_id],
|
|
21
|
+
name: "idx_a2a_tasks_owner_task"
|
|
22
|
+
add_index :a2a_rails_tasks, [:owner_id, :context_id, :status_timestamp],
|
|
23
|
+
name: "idx_a2a_tasks_owner_context_time"
|
|
24
|
+
add_index :a2a_rails_tasks, [:owner_id, :state, :status_timestamp],
|
|
25
|
+
name: "idx_a2a_tasks_owner_state_time"
|
|
26
|
+
add_index :a2a_rails_tasks, [:owner_id, :status_timestamp],
|
|
27
|
+
name: "idx_a2a_tasks_owner_time"
|
|
28
|
+
add_index :a2a_rails_tasks, :expires_at,
|
|
29
|
+
name: "idx_a2a_tasks_expires_at"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
A2A::Rails.configure do |config|
|
|
2
2
|
config.agent = "YourAgent"
|
|
3
3
|
config.public_base_url = ENV["A2A_PUBLIC_BASE_URL"]
|
|
4
|
+
|
|
5
|
+
# Production/staging A2A requests fail closed unless the host configures
|
|
6
|
+
# config.authenticate_request and matching Agent Card security metadata.
|
|
7
|
+
# See: https://github.com/cuichangquan/a2a-rails/blob/main/docs/guides/authentication.md
|
|
4
8
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :a2a do
|
|
4
|
+
namespace :rails do
|
|
5
|
+
namespace :tasks do
|
|
6
|
+
desc "Delete expired a2a-rails Tasks in bounded batches"
|
|
7
|
+
task prune: :environment do
|
|
8
|
+
store = A2A::Rails.configuration.resolve_task_store
|
|
9
|
+
unless store.respond_to?(:prune_expired)
|
|
10
|
+
abort "Configured a2a-rails Task Store does not support pruning"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
max_batches = Integer(ENV.fetch("A2A_TASK_PRUNE_MAX_BATCHES", "100"), 10)
|
|
14
|
+
abort "A2A_TASK_PRUNE_MAX_BATCHES must be positive" unless max_batches.positive?
|
|
15
|
+
|
|
16
|
+
total = 0
|
|
17
|
+
batches = 0
|
|
18
|
+
|
|
19
|
+
while batches < max_batches
|
|
20
|
+
deleted = store.prune_expired
|
|
21
|
+
break if deleted.zero?
|
|
22
|
+
|
|
23
|
+
total += deleted
|
|
24
|
+
batches += 1
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
stats = store.respond_to?(:maintenance_stats) ? store.maintenance_stats : {}
|
|
28
|
+
remaining = stats[:expired]
|
|
29
|
+
|
|
30
|
+
puts "a2a-rails Task prune: deleted=#{total} batches=#{batches}" +
|
|
31
|
+
(remaining.nil? ? "" : " expired_remaining=#{remaining}")
|
|
32
|
+
rescue ArgumentError => error
|
|
33
|
+
abort error.message
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Print aggregate a2a-rails Task maintenance counts"
|
|
37
|
+
task stats: :environment do
|
|
38
|
+
store = A2A::Rails.configuration.resolve_task_store
|
|
39
|
+
unless store.respond_to?(:maintenance_stats)
|
|
40
|
+
abort "Configured a2a-rails Task Store does not support maintenance stats"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
stats = store.maintenance_stats
|
|
44
|
+
puts [
|
|
45
|
+
"a2a-rails Task stats:",
|
|
46
|
+
"total=#{stats.fetch(:total)}",
|
|
47
|
+
"active=#{stats.fetch(:active)}",
|
|
48
|
+
"terminal=#{stats.fetch(:terminal)}",
|
|
49
|
+
"expired=#{stats.fetch(:expired)}"
|
|
50
|
+
].join(" ")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: a2a-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0.rc2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- cuichangquan
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: agent2agent
|
|
@@ -43,6 +43,26 @@ dependencies:
|
|
|
43
43
|
- - "<"
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
45
|
version: '8.2'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: activejob
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '8.0'
|
|
53
|
+
- - "<"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '8.2'
|
|
56
|
+
type: :runtime
|
|
57
|
+
prerelease: false
|
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '8.0'
|
|
63
|
+
- - "<"
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '8.2'
|
|
46
66
|
- !ruby/object:Gem::Dependency
|
|
47
67
|
name: json
|
|
48
68
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -97,6 +117,26 @@ dependencies:
|
|
|
97
117
|
- - "<"
|
|
98
118
|
- !ruby/object:Gem::Version
|
|
99
119
|
version: '8.2'
|
|
120
|
+
- !ruby/object:Gem::Dependency
|
|
121
|
+
name: activerecord
|
|
122
|
+
requirement: !ruby/object:Gem::Requirement
|
|
123
|
+
requirements:
|
|
124
|
+
- - ">="
|
|
125
|
+
- !ruby/object:Gem::Version
|
|
126
|
+
version: '8.0'
|
|
127
|
+
- - "<"
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '8.2'
|
|
130
|
+
type: :development
|
|
131
|
+
prerelease: false
|
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - ">="
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: '8.0'
|
|
137
|
+
- - "<"
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: '8.2'
|
|
100
140
|
- !ruby/object:Gem::Dependency
|
|
101
141
|
name: minitest
|
|
102
142
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -125,6 +165,46 @@ dependencies:
|
|
|
125
165
|
- - "~>"
|
|
126
166
|
- !ruby/object:Gem::Version
|
|
127
167
|
version: '13.2'
|
|
168
|
+
- !ruby/object:Gem::Dependency
|
|
169
|
+
name: sqlite3
|
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
|
171
|
+
requirements:
|
|
172
|
+
- - ">="
|
|
173
|
+
- !ruby/object:Gem::Version
|
|
174
|
+
version: '2.1'
|
|
175
|
+
- - "<"
|
|
176
|
+
- !ruby/object:Gem::Version
|
|
177
|
+
version: '3'
|
|
178
|
+
type: :development
|
|
179
|
+
prerelease: false
|
|
180
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
181
|
+
requirements:
|
|
182
|
+
- - ">="
|
|
183
|
+
- !ruby/object:Gem::Version
|
|
184
|
+
version: '2.1'
|
|
185
|
+
- - "<"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '3'
|
|
188
|
+
- !ruby/object:Gem::Dependency
|
|
189
|
+
name: puma
|
|
190
|
+
requirement: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">="
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '6.6'
|
|
195
|
+
- - "<"
|
|
196
|
+
- !ruby/object:Gem::Version
|
|
197
|
+
version: '8'
|
|
198
|
+
type: :development
|
|
199
|
+
prerelease: false
|
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
201
|
+
requirements:
|
|
202
|
+
- - ">="
|
|
203
|
+
- !ruby/object:Gem::Version
|
|
204
|
+
version: '6.6'
|
|
205
|
+
- - "<"
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '8'
|
|
128
208
|
description: Expose Rails applications as A2A agents while keeping protocol SDK details
|
|
129
209
|
behind an internal adapter boundary.
|
|
130
210
|
executables: []
|
|
@@ -141,28 +221,39 @@ files:
|
|
|
141
221
|
- lib/a2a-rails.rb
|
|
142
222
|
- lib/a2a/rails/agent.rb
|
|
143
223
|
- lib/a2a/rails/agent_card/builder.rb
|
|
224
|
+
- lib/a2a/rails/agent_card/security.rb
|
|
144
225
|
- lib/a2a/rails/agent_card/validator.rb
|
|
226
|
+
- lib/a2a/rails/authentication.rb
|
|
145
227
|
- lib/a2a/rails/configuration.rb
|
|
146
228
|
- lib/a2a/rails/dispatcher.rb
|
|
147
229
|
- lib/a2a/rails/engine.rb
|
|
148
230
|
- lib/a2a/rails/errors.rb
|
|
231
|
+
- lib/a2a/rails/execution_plan.rb
|
|
232
|
+
- lib/a2a/rails/file_artifact.rb
|
|
149
233
|
- lib/a2a/rails/protocol/adapter.rb
|
|
150
234
|
- lib/a2a/rails/protocol/agent2agent_adapter.rb
|
|
151
235
|
- lib/a2a/rails/protocol/request_handler.rb
|
|
152
236
|
- lib/a2a/rails/protocol/task_mapper.rb
|
|
237
|
+
- lib/a2a/rails/request_guard.rb
|
|
153
238
|
- lib/a2a/rails/runtime.rb
|
|
154
239
|
- lib/a2a/rails/skill.rb
|
|
155
240
|
- lib/a2a/rails/task.rb
|
|
241
|
+
- lib/a2a/rails/task/active_record_store.rb
|
|
156
242
|
- lib/a2a/rails/task/artifact_mapper.rb
|
|
157
243
|
- lib/a2a/rails/task/lifecycle.rb
|
|
158
244
|
- lib/a2a/rails/task/memory_store.rb
|
|
159
245
|
- lib/a2a/rails/task/result_mapper.rb
|
|
160
246
|
- lib/a2a/rails/task/store.rb
|
|
247
|
+
- lib/a2a/rails/task_execution_arguments.rb
|
|
248
|
+
- lib/a2a/rails/task_execution_job.rb
|
|
161
249
|
- lib/a2a/rails/version.rb
|
|
162
250
|
- lib/generators/a2a/rails/agent_generator.rb
|
|
163
251
|
- lib/generators/a2a/rails/install_generator.rb
|
|
252
|
+
- lib/generators/a2a/rails/task_store_generator.rb
|
|
164
253
|
- lib/generators/a2a/rails/templates/agent.rb.tt
|
|
254
|
+
- lib/generators/a2a/rails/templates/create_a2a_rails_tasks.rb.tt
|
|
165
255
|
- lib/generators/a2a/rails/templates/initializer.rb.tt
|
|
256
|
+
- lib/tasks/a2a_rails_tasks.rake
|
|
166
257
|
homepage: https://github.com/cuichangquan/a2a-rails
|
|
167
258
|
licenses:
|
|
168
259
|
- MIT
|
|
@@ -186,7 +277,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
186
277
|
- !ruby/object:Gem::Version
|
|
187
278
|
version: '0'
|
|
188
279
|
requirements: []
|
|
189
|
-
rubygems_version: 3.6.
|
|
280
|
+
rubygems_version: 3.6.9
|
|
190
281
|
specification_version: 4
|
|
191
282
|
summary: Rails-native integration for exposing Rails applications as A2A agents
|
|
192
283
|
test_files: []
|