act_as_agent 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: baa7b8d52de19e37dbf7757ea966d1434f7b117a4dc5bd0f7f2362c82cfc5158
4
- data.tar.gz: 58daeed66183080bf5005b6669a36d5cf9d48f6bd59e2711dc74b210715390b8
3
+ metadata.gz: 7f0a2fea9ab22df1f6420509ac58b4e666fe2b935fa4a452a651f366a50b9201
4
+ data.tar.gz: 1b1b554adc81bbfbcb325fa7abbaf2b7b06e06428e61123aabbb264fc718bc2f
5
5
  SHA512:
6
- metadata.gz: a386637550b572da4b292e92568d88a54e0e31d9612e3aa70ef7dd200a98837a8394267e7bc569f46aa1c33a86306281600b98123eed1db625c7fec9ebc8e89c
7
- data.tar.gz: 47a79f122f12255f34d1e156b597550c9f7e41da8db8d73dcb87889c8aad7968eff051946ee1c0feca29ae73aa771ef56e6866b092bb6c172e4380484bc1a61f
6
+ metadata.gz: dc8afbb5eb5106ca85c1fe5f65199fd21f25e0450064b8fd519d545ac88d92120c07b18ba4cdfc87b5c28ee33c326233ca6442305b95e0cab1c939d470f5367a
7
+ data.tar.gz: a8311e8f892629d8d8b51e62c322e77e1ab989ae45bedc41286c9805327ed3f892e5f66d6be77c75e96a17329d4651ca021a2e89c1d4e7048fc4a1f1b477c671
data/Gemfile CHANGED
@@ -8,6 +8,6 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
  gem "rspec", "~> 3.0"
10
10
  gem "rubocop", "~> 1.21"
11
+ gem "simplecov", "~> 0.22.0"
11
12
  gem "vcr", "~> 6.3"
12
-
13
13
  gem "webmock", "~> 3.26"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- act_as_agent (0.1.0)
4
+ act_as_agent (0.2.0)
5
5
  act_as_api_client (~> 1.3.1)
6
6
 
7
7
  GEM
@@ -18,6 +18,7 @@ GEM
18
18
  bigdecimal
19
19
  rexml
20
20
  diff-lcs (1.6.2)
21
+ docile (1.4.1)
21
22
  event_stream_parser (1.0.0)
22
23
  hashdiff (1.2.1)
23
24
  json (2.16.0)
@@ -62,6 +63,12 @@ GEM
62
63
  parser (>= 3.3.7.2)
63
64
  prism (~> 1.4)
64
65
  ruby-progressbar (1.13.0)
66
+ simplecov (0.22.0)
67
+ docile (~> 1.1)
68
+ simplecov-html (~> 0.11)
69
+ simplecov_json_formatter (~> 0.1)
70
+ simplecov-html (0.13.2)
71
+ simplecov_json_formatter (0.1.4)
65
72
  unicode-display_width (3.2.0)
66
73
  unicode-emoji (~> 4.1)
67
74
  unicode-emoji (4.1.0)
@@ -81,6 +88,7 @@ DEPENDENCIES
81
88
  rake (~> 13.0)
82
89
  rspec (~> 3.0)
83
90
  rubocop (~> 1.21)
91
+ simplecov (~> 0.22.0)
84
92
  vcr (~> 6.3)
85
93
  webmock (~> 3.26)
86
94
 
data/idea.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MyCodingAgent
4
+ include ActAsAgent::Base
5
+
6
+ tools [edit_file, read_file, list_files, run_rspec]
7
+
8
+ def task_with; end
9
+ end
10
+
11
+ class BookAuthorAgent
12
+ include ActAsAgent::Base
13
+
14
+ tools [edit_file, read_file, list_files]
15
+
16
+ def task_with; end
17
+ end
18
+
19
+ class GameCreatorAgent
20
+ include ActAsAgent::Base
21
+
22
+ tools [edit_file, read_file, list_files]
23
+
24
+ def task_with; end
25
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "act_as_api_client"
4
+
5
+ module ActAsAgent
6
+ module ApiClients
7
+ class AnthropicClient < ApiClient
8
+ act_as_api_client for: %i[anthropic messages]
9
+
10
+ def initialize(key:, max_tokens:)
11
+ super()
12
+
13
+ options[:x_api_key] = key
14
+ options[:max_tokens] = max_tokens
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,16 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "act_as_agent/providers/anthropic"
4
+
3
5
  module ActAsAgent
4
6
  module Base
5
7
  def self.included(base)
6
8
  base.extend(ClassMethods)
7
9
  end
8
10
 
9
- def run(); end
11
+ def run(args)
12
+ llm_provider.request(content: args[:task])
13
+ end
14
+
15
+ def tools
16
+ @tools ||= self.class.instance_variable_get("@tools") || []
17
+ end
18
+
19
+ def llm_provider
20
+ klass = self.class.instance_variable_get("@llm_provider")
21
+ @llm_provider ||= if klass == ActAsAgent::Providers::Anthropic
22
+ key = llm_provider_options.fetch(:key, nil)
23
+ ActAsAgent::Providers::Anthropic.new(tools: tools, key: key)
24
+ end
25
+ end
26
+
27
+ def llm_provider_options
28
+ @llm_provider_options ||= self.class.instance_variable_get("@llm_provider_options")
29
+ end
10
30
 
11
31
  module ClassMethods
12
- def tools(list)
13
- define_method(:tools) { list }
32
+ def tools(tls)
33
+ instance_variable_set("@tools", tls)
34
+ end
35
+
36
+ def llm_provider(klass, args)
37
+ instance_variable_set("@llm_provider", klass)
38
+ instance_variable_set("@llm_provider_options", args.fetch(:with, {}))
14
39
  end
15
40
  end
16
41
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActAsAgent
4
+ module Errors
5
+ module Providers
6
+ class AuthenticationError < StandardError
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActAsAgent
4
+ module Errors
5
+ class ToolIncorrectArgsError < StandardError
6
+ end
7
+ end
8
+ end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # https://docs.claude.com/en/api/messages#body-tools
4
4
  # https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview#tool-use-examples
5
+ require "act_as_agent/api_clients/anthropic_api_client"
6
+ require "act_as_agent/errors/providers/anthropic/authentication_error"
5
7
 
6
8
  module ActAsAgent
7
9
  module Providers
@@ -14,10 +16,10 @@ module ActAsAgent
14
16
  @config = { key: key, max_tokens: max_tokens }
15
17
  @tools = tools
16
18
  @max_tokens = max_tokens
17
- @client = AnthropicClient.new(key: key, max_tokens: max_tokens)
19
+ @client = ActAsAgent::ApiClients::AnthropicClient.new(key: key, max_tokens: max_tokens)
18
20
  end
19
21
 
20
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
22
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
21
23
  def request(content:)
22
24
  content = [{ role: "user", content: content }] unless content.is_a?(Array)
23
25
 
@@ -28,28 +30,35 @@ module ActAsAgent
28
30
  max_tokens: max_tokens
29
31
  )
30
32
 
31
- tool_responses = []
33
+ if response["type"] == "error"
34
+ case response["error"]["type"]
35
+ when "authentication_error"
36
+ return ActAsAgent::Errors::Providers::AuthenticationError
37
+ end
38
+ end
39
+
40
+ return response if response["stop_reason"] == "end_turn"
32
41
 
33
- response["content"].each do |message|
34
- next unless message["type"] == "tool_use"
42
+ tool_responses = response["content"].each_with_object([]) do |message, memo|
43
+ next memo unless message["type"] == "tool_use"
35
44
 
36
45
  @tools.each do |tool|
37
46
  next unless tool.name == message["name"]
38
47
 
39
- tool_responses << {
48
+ memo << {
40
49
  "role" => "assistant",
41
50
  "content" => [
42
51
  message
43
52
  ]
44
53
  }
45
54
 
46
- tool_responses << {
55
+ memo << {
47
56
  role: "user",
48
57
  content: [
49
58
  {
50
59
  type: "tool_result",
51
60
  tool_use_id: message["id"],
52
- content: tool.call(message["input"])
61
+ content: tool.call(message["input"]).to_s
53
62
  }
54
63
  ]
55
64
  }
@@ -57,10 +66,8 @@ module ActAsAgent
57
66
  end
58
67
 
59
68
  request(content: content + tool_responses) unless tool_responses.empty?
60
-
61
- response["content"]
62
69
  end
63
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
70
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
64
71
 
65
72
  private
66
73
 
@@ -76,14 +83,3 @@ module ActAsAgent
76
83
  end
77
84
  end
78
85
  end
79
-
80
- class AnthropicClient < ApiClient
81
- act_as_api_client for: %i[anthropic messages]
82
-
83
- def initialize(key:, max_tokens:)
84
- super()
85
-
86
- options[:x_api_key] = key
87
- options[:max_tokens] = max_tokens
88
- end
89
- end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "act_as_agent/errors/tool_incorrect_args_error"
4
+
5
+ module ActAsAgent
6
+ module Tools
7
+ class ListFiles
8
+ ERROR = ActAsAgent::Errors::ToolIncorrectArgsError
9
+
10
+ attr_reader :root_folder
11
+
12
+ def initialize(root_folder: nil)
13
+ @root_folder = root_folder
14
+ end
15
+
16
+ def name
17
+ self.class.to_s.gsub("::", "__")
18
+ end
19
+
20
+ def description
21
+ "List files in the directory and all subdirectories. Pass the path to lookup"
22
+ end
23
+
24
+ def input_schema
25
+ {
26
+ type: "object",
27
+ properties: {
28
+ root_folder: { type: "string",
29
+ description: "The root folder of the list folder. By default it will use current folder." }
30
+ },
31
+ required: []
32
+ }
33
+ end
34
+
35
+ def call(args = {})
36
+ path = args.fetch("path", nil)
37
+
38
+ return Dir.glob(path) unless path.nil? || path.chomp == ""
39
+ return Dir.glob(root_folder) unless root_folder.nil?
40
+
41
+ ERROR.new("Incorrect params have been given to list files tool")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "act_as_agent/errors/tool_incorrect_args_error"
4
+
5
+ module ActAsAgent
6
+ module Tools
7
+ class ReadFile
8
+ ERROR = ActAsAgent::Errors::ToolIncorrectArgsError
9
+
10
+ attr_reader :file_path
11
+
12
+ def initialize(file_path: nil)
13
+ @file_path = file_path
14
+ end
15
+
16
+ def name
17
+ self.class.to_s.gsub("::", "__")
18
+ end
19
+
20
+ def description
21
+ "Read file by the given path"
22
+ end
23
+
24
+ def input_schema
25
+ {
26
+ type: "object",
27
+ properties: {
28
+ file_path: { type: "string",
29
+ description: "File path to read" }
30
+ },
31
+ required: []
32
+ }
33
+ end
34
+
35
+ def call(args = {})
36
+ path = args.fetch("file_path", nil)
37
+
38
+ return File.read(path) unless path.nil? || path.chomp == ""
39
+ return File.read(file_path) unless file_path.nil?
40
+
41
+ ERROR.new("Incorrect params have been given to list files tool")
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/act_as_agent.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "act_as_agent/base"
4
- require "act_as_api_client"
5
4
 
6
5
  module ActAsAgent
7
6
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: act_as_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Rukomoynikov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-08 00:00:00.000000000 Z
11
+ date: 2025-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: act_as_api_client
@@ -44,10 +44,16 @@ files:
44
44
  - LICENSE.txt
45
45
  - README.md
46
46
  - Rakefile
47
+ - idea.rb
47
48
  - idea.text
48
49
  - lib/act_as_agent.rb
50
+ - lib/act_as_agent/api_clients/anthropic_api_client.rb
49
51
  - lib/act_as_agent/base.rb
52
+ - lib/act_as_agent/errors/providers/anthropic/authentication_error.rb
53
+ - lib/act_as_agent/errors/tool_incorrect_args_error.rb
50
54
  - lib/act_as_agent/providers/anthropic.rb
55
+ - lib/act_as_agent/tools/list_files.rb
56
+ - lib/act_as_agent/tools/read_file.rb
51
57
  - sig/act_as_agent.rbs
52
58
  homepage: https://github.com/Rukomoynikov/act_as_agent
53
59
  licenses: