ruboty-ai_agent 0.3.0 → 0.4.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 +7 -0
- data/Gemfile +2 -0
- data/bin/ruboty +2 -0
- data/lib/ruboty/ai_agent/actions/chat.rb +14 -2
- data/lib/ruboty/ai_agent/chat_thread_messages.rb +6 -3
- data/lib/ruboty/ai_agent/commands/usage.rb +1 -3
- data/lib/ruboty/ai_agent/commands.rb +1 -1
- data/lib/ruboty/ai_agent/llm/openai/model.rb +1 -1
- data/lib/ruboty/ai_agent/settings.rb +28 -0
- data/lib/ruboty/ai_agent/tool_definitions/base.rb +4 -0
- data/lib/ruboty/ai_agent/tool_definitions/bot_help.rb +89 -0
- data/lib/ruboty/ai_agent/tool_definitions/fetch.rb +142 -0
- data/lib/ruboty/ai_agent/tool_definitions.rb +6 -2
- data/lib/ruboty/ai_agent/version.rb +1 -1
- data/lib/ruboty/ai_agent.rb +3 -0
- data/lib/ruboty/handlers/ai_agent.rb +3 -0
- data/script/generate-memorized-ivar-rbs.rb +27 -4
- data/sig/generated/ruboty/ai_agent/actions/chat.rbs +4 -0
- data/sig/generated/ruboty/ai_agent/chat_thread_messages.rbs +3 -2
- data/sig/generated/ruboty/ai_agent/settings.rbs +21 -0
- data/sig/generated/ruboty/ai_agent/tool_definitions/base.rbs +2 -0
- data/sig/generated/ruboty/ai_agent/tool_definitions/bot_help.rbs +23 -0
- data/sig/generated/ruboty/ai_agent/tool_definitions/fetch.rbs +43 -0
- data/sig/generated/ruboty/ai_agent.rbs +2 -0
- data/sig/generated-by-scripts/memorized_ivars.rbs +8 -0
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab07f82523eaf799691d9b03457bfa01751d0b0d1864e69bbbfc8661d34a0fef
|
4
|
+
data.tar.gz: 9e51ee2e35c00010df295626b8749019feefc67eab4d5fe396913eb1f468e433
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: beda5fe21c74e2def519c4e7d9bef74144fffb5daa7ea2334debc065218ab319eead0be9db7a36fda3ed4909bd16b54dab8f289dfd94da77b971c20b20f5a40e
|
7
|
+
data.tar.gz: 1b7a5ff752355974c23a807c6360d2a8454d19e0afc7e0546e253c99e9ed79a2731aa32a02963471449052c81f7e1635babf7e16d093cc8708ba71889638ae4c
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
## Unreleased
|
2
|
+
## 0.4.0
|
3
|
+
|
4
|
+
- Add `bot_help` builtin tool to retrieve Ruboty's help information.
|
5
|
+
- Add `fetch` builtin tool for fetching web content.
|
6
|
+
- Fix `/usage` command to show token usage of last message.
|
7
|
+
- Format tool call logs for better readability.
|
8
|
+
|
2
9
|
## 0.3.0
|
3
10
|
|
4
11
|
- Add think tool.
|
data/Gemfile
CHANGED
data/bin/ruboty
CHANGED
@@ -82,10 +82,10 @@ module Ruboty
|
|
82
82
|
|
83
83
|
chat_thread.messages.compact(llm:) if chat_thread.messages.over_auto_compact_threshold?
|
84
84
|
when :tool_call
|
85
|
-
message.reply("Calling tool #{event[:tool].name} with arguments #{event[:tool_arguments]&.to_json}") unless event[:tool].silent?
|
85
|
+
message.reply(indent_with_quotation("Calling tool #{event[:tool].name} with arguments #{truncate(event[:tool_arguments]&.to_json, max: 100)}")) unless event[:tool].silent?
|
86
86
|
when :tool_response
|
87
87
|
chat_thread.messages << event[:message]
|
88
|
-
message.reply("Tool response: #{event[:tool_response]
|
88
|
+
message.reply(indent_with_quotation("Tool response: #{truncate(event[:tool_response], max: 100)}")) unless event[:tool].silent?
|
89
89
|
end
|
90
90
|
end
|
91
91
|
rescue StandardError => e
|
@@ -95,6 +95,18 @@ module Ruboty
|
|
95
95
|
message.reply("エラーが発生しました: #{e.message}")
|
96
96
|
end
|
97
97
|
end
|
98
|
+
|
99
|
+
def truncate(text, max:)
|
100
|
+
if text.length > max
|
101
|
+
"#{text.slice(0..max)}..."
|
102
|
+
else
|
103
|
+
text
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def indent_with_quotation(text, quota = '> ')
|
108
|
+
text.lines.map { |line| "#{quota}#{line}" }.join
|
109
|
+
end
|
98
110
|
end
|
99
111
|
end
|
100
112
|
end
|
@@ -11,12 +11,15 @@ module Ruboty
|
|
11
11
|
store(message, key: (keys.last.to_s.to_i || -1) + 1)
|
12
12
|
end
|
13
13
|
|
14
|
+
def token_usage #: TokenUsage?
|
15
|
+
all_values.reverse_each.find(&:token_usage)&.token_usage
|
16
|
+
end
|
17
|
+
|
14
18
|
alias << add
|
15
19
|
|
16
20
|
# Check if any message's token usage exceeds auto compact threshold
|
17
|
-
|
18
|
-
|
19
|
-
all_values.any? { |message| message.token_usage&.over_auto_compact_threshold? }
|
21
|
+
def over_auto_compact_threshold? #: boolish
|
22
|
+
token_usage&.over_auto_compact_threshold?
|
20
23
|
end
|
21
24
|
|
22
25
|
# Compact chat messages by summarizing them
|
@@ -8,9 +8,7 @@ module Ruboty
|
|
8
8
|
on(%r{/usage}, name: 'show_usage', description: 'Show token usage information for the latest AI response')
|
9
9
|
|
10
10
|
def call(*) #: void
|
11
|
-
|
12
|
-
|
13
|
-
token_usage = latest_message&.token_usage
|
11
|
+
token_usage = chat_thread.messages.token_usage
|
14
12
|
|
15
13
|
if token_usage
|
16
14
|
usage_text = "Token usage: #{format_number(token_usage.prompt_tokens)} (prompt) + #{format_number(token_usage.completion_tokens)} (completion) = #{format_number(token_usage.total_tokens)} (total)"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ruboty
|
4
|
+
module AiAgent
|
5
|
+
# Provide library-wide settings.
|
6
|
+
class Settings
|
7
|
+
# Provide access to settings instance.
|
8
|
+
module Accessor
|
9
|
+
def settings #: Ruboty::AiAgent::Settings
|
10
|
+
Settings.instance
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @rbs %a{memorized}
|
15
|
+
def self.instance #: Ruboty::AiAgent::Settings
|
16
|
+
@instance ||= Settings.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def max_tokens #: Integer?
|
20
|
+
ENV['AI_AGENT_MAX_TOKENS']&.to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def auto_compact_threshold #: Float
|
24
|
+
ENV.fetch('AI_AGENT_AUTO_COMPACT_THRESHOLD', '80').to_f
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ruboty
|
4
|
+
module AiAgent
|
5
|
+
module ToolDefinitions
|
6
|
+
# Tool for retrieving Ruboty help information
|
7
|
+
class BotHelp < Base
|
8
|
+
self.tool_name = 'bot_help'
|
9
|
+
self.tool_title = 'Show help information about this bot (you)'
|
10
|
+
|
11
|
+
self.tool_description = <<~TEXT
|
12
|
+
Get help information about available patterns of this bot (you).
|
13
|
+
This returns the same information as the 'help' command in Ruboty.
|
14
|
+
|
15
|
+
# Hint
|
16
|
+
|
17
|
+
- You are a Ruboty bot. You can find available commands by using this tool.
|
18
|
+
- If user asks for what you can do or usage (e.g. "Tell me the usage", "How do I use it?"), use this tool to respond.
|
19
|
+
- If user asks for specific commands, use the 'filter' argument to search for them.
|
20
|
+
- If user typed a command that you don't know, use this tool to find out the correct command.
|
21
|
+
TEXT
|
22
|
+
|
23
|
+
self.tool_input_schema = {
|
24
|
+
type: 'object',
|
25
|
+
properties: {
|
26
|
+
filter: {
|
27
|
+
type: 'string',
|
28
|
+
description: 'Optional filter to search for specific commands (e.g., "mcp", "ai", "ping")'
|
29
|
+
}
|
30
|
+
},
|
31
|
+
required: []
|
32
|
+
}
|
33
|
+
|
34
|
+
# @rbs arguments: Hash[String, untyped]
|
35
|
+
# @rbs return: String?
|
36
|
+
def call(arguments)
|
37
|
+
filter = arguments['filter']
|
38
|
+
|
39
|
+
descriptions = filtered_descriptions(filter)
|
40
|
+
|
41
|
+
if descriptions.empty?
|
42
|
+
if filter
|
43
|
+
"No description matched to '#{filter}'"
|
44
|
+
else
|
45
|
+
'No commands available'
|
46
|
+
end
|
47
|
+
else
|
48
|
+
descriptions.join("\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# @rbs filter: String?
|
55
|
+
# @rbs return: Array[String]
|
56
|
+
def filtered_descriptions(filter)
|
57
|
+
descriptions = all_descriptions
|
58
|
+
|
59
|
+
if filter
|
60
|
+
descriptions.select! do |description|
|
61
|
+
description.include?(filter)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
descriptions
|
66
|
+
end
|
67
|
+
|
68
|
+
# @rbs return: Array[String]
|
69
|
+
def all_descriptions
|
70
|
+
actions = Ruboty.actions.reject(&:hidden?)
|
71
|
+
|
72
|
+
# Sort by description for consistent ordering
|
73
|
+
sorted_actions = begin
|
74
|
+
actions.sort_by(&:description)
|
75
|
+
rescue ArgumentError
|
76
|
+
# Fallback if sorting fails (e.g., in tests with mocks)
|
77
|
+
actions
|
78
|
+
end
|
79
|
+
|
80
|
+
sorted_actions.map do |action|
|
81
|
+
prefix = ''
|
82
|
+
prefix += "#{request.message.robot.name} " unless action.all?
|
83
|
+
"#{prefix}#{action.pattern.inspect} - #{action.description}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'net/https'
|
6
|
+
|
7
|
+
module Ruboty
|
8
|
+
module AiAgent
|
9
|
+
module ToolDefinitions
|
10
|
+
# Fetch and extract readable content from web pages using ruby-readability
|
11
|
+
class Fetch < Base
|
12
|
+
class FetchError < StandardError; end
|
13
|
+
|
14
|
+
self.tool_name = 'fetch'
|
15
|
+
self.tool_title = 'Fetch Web Page Content'
|
16
|
+
|
17
|
+
self.tool_description = <<~TEXT
|
18
|
+
Fetch and extract readable content from a web page using ruby-readability.
|
19
|
+
This tool downloads the HTML from a URL and extracts the main readable text,
|
20
|
+
filtering out navigation, ads, and other boilerplate content.
|
21
|
+
TEXT
|
22
|
+
|
23
|
+
self.tool_input_schema = {
|
24
|
+
type: 'object',
|
25
|
+
properties: {
|
26
|
+
url: {
|
27
|
+
type: 'string',
|
28
|
+
description: 'The URL of the web page to fetch.'
|
29
|
+
}
|
30
|
+
},
|
31
|
+
required: ['url']
|
32
|
+
}
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# @rbs @available: bool
|
36
|
+
|
37
|
+
def avaliable!
|
38
|
+
@available = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def not_avaliable!
|
42
|
+
@available = false
|
43
|
+
end
|
44
|
+
|
45
|
+
def available? #: boolish
|
46
|
+
@available
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @rbs arguments: Hash[String, untyped]
|
51
|
+
# @rbs return: String?
|
52
|
+
def call(arguments)
|
53
|
+
url = arguments['url']
|
54
|
+
|
55
|
+
return 'Error: Please provide a URL parameter.' unless url
|
56
|
+
|
57
|
+
url = normalize_url(url.to_s)
|
58
|
+
return 'Error: Invalid URL format.' unless valid_url?(url)
|
59
|
+
|
60
|
+
content = begin
|
61
|
+
fetch_content(url)
|
62
|
+
rescue StandardError => e
|
63
|
+
raise FetchError, e.message
|
64
|
+
end
|
65
|
+
|
66
|
+
readable_content = extract_readable_content(content)
|
67
|
+
|
68
|
+
if readable_content.strip.empty?
|
69
|
+
"No readable content found on the page: #{url}"
|
70
|
+
else
|
71
|
+
"Content from #{url}:\n\n#{readable_content}"
|
72
|
+
end
|
73
|
+
rescue FetchError => e
|
74
|
+
"Failed to fetch content from #{url}: #{e.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# @rbs url: String
|
80
|
+
# @rbs return: String
|
81
|
+
def normalize_url(url)
|
82
|
+
url = url.strip
|
83
|
+
url = "https://#{url}" unless url.match?(%r{\Ahttps?://})
|
84
|
+
url
|
85
|
+
end
|
86
|
+
|
87
|
+
# @rbs url: String
|
88
|
+
# @rbs return: bool
|
89
|
+
def valid_url?(url)
|
90
|
+
uri = URI.parse(url)
|
91
|
+
return false unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
92
|
+
return false if uri.host.nil?
|
93
|
+
|
94
|
+
true
|
95
|
+
rescue URI::InvalidURIError
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
# @rbs url: String
|
100
|
+
# @rbs return: String
|
101
|
+
def fetch_content(url)
|
102
|
+
uri = URI.parse(url)
|
103
|
+
host = uri.host
|
104
|
+
port = uri.port
|
105
|
+
raise 'Invalid URL: missing host' if host.nil?
|
106
|
+
|
107
|
+
http = Net::HTTP.new(host, port)
|
108
|
+
http.use_ssl = true if uri.scheme == 'https'
|
109
|
+
http.open_timeout = 10
|
110
|
+
http.read_timeout = 30
|
111
|
+
|
112
|
+
path = uri.path
|
113
|
+
path = '/' if path.nil? || path.empty?
|
114
|
+
request = Net::HTTP::Get.new(path)
|
115
|
+
request['User-Agent'] = 'Mozilla/5.0 (compatible; RubotyAI/1.0)'
|
116
|
+
|
117
|
+
response = http.request(request)
|
118
|
+
|
119
|
+
raise "HTTP error: #{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)
|
120
|
+
|
121
|
+
response.body
|
122
|
+
end
|
123
|
+
|
124
|
+
# @rbs content: String
|
125
|
+
# @rbs return: String
|
126
|
+
def extract_readable_content(content)
|
127
|
+
document = Readability::Document.new(content)
|
128
|
+
document.content
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Add Fetch tool only if ruby-readability is available
|
136
|
+
begin
|
137
|
+
require 'ruby-readability'
|
138
|
+
Ruboty::AiAgent::ToolDefinitions::Fetch.avaliable!
|
139
|
+
rescue LoadError
|
140
|
+
# ruby-readability not available, skip Fetch tool
|
141
|
+
Ruboty::AiAgent::ToolDefinitions::Fetch.not_avaliable!
|
142
|
+
end
|
@@ -5,14 +5,18 @@ module Ruboty
|
|
5
5
|
# Tool Definitions for AI Agent
|
6
6
|
module ToolDefinitions
|
7
7
|
autoload :Base, 'ruboty/ai_agent/tool_definitions/base'
|
8
|
+
autoload :Fetch, 'ruboty/ai_agent/tool_definitions/fetch'
|
8
9
|
autoload :Think, 'ruboty/ai_agent/tool_definitions/think'
|
10
|
+
autoload :BotHelp, 'ruboty/ai_agent/tool_definitions/bot_help'
|
9
11
|
|
10
12
|
# @rbs request: Request
|
11
13
|
# @rbs return: Array[Base]
|
12
14
|
def self.builtins(request:)
|
13
15
|
[
|
14
|
-
Think
|
15
|
-
|
16
|
+
Think,
|
17
|
+
BotHelp,
|
18
|
+
Fetch
|
19
|
+
].select(&:available?).map { |tool_def| tool_def.new(request:) }
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
data/lib/ruboty/ai_agent.rb
CHANGED
@@ -29,6 +29,7 @@ module Ruboty
|
|
29
29
|
autoload :Recordable, 'ruboty/ai_agent/recordable'
|
30
30
|
autoload :RecordSet, 'ruboty/ai_agent/record_set'
|
31
31
|
autoload :Request, 'ruboty/ai_agent/request'
|
32
|
+
autoload :Settings, 'ruboty/ai_agent/settings'
|
32
33
|
autoload :TokenUsage, 'ruboty/ai_agent/token_usage'
|
33
34
|
autoload :Tool, 'ruboty/ai_agent/tool'
|
34
35
|
autoload :ToolDefinitions, 'ruboty/ai_agent/tool_definitions'
|
@@ -41,6 +42,8 @@ module Ruboty
|
|
41
42
|
autoload :UserMcpToolsCaches, 'ruboty/ai_agent/user_mcp_tools_caches'
|
42
43
|
autoload :UserPromptCommandDefinitions, 'ruboty/ai_agent/user_prompt_command_definitions'
|
43
44
|
|
45
|
+
extend Settings::Accessor
|
46
|
+
|
44
47
|
# Ensure all recordables are loaded
|
45
48
|
[
|
46
49
|
CachedValue,
|
@@ -9,6 +9,9 @@ module Ruboty
|
|
9
9
|
env :OPENAI_API_KEY, 'Pass your OpenAI API Key'
|
10
10
|
env :OPENAI_MODEL, 'OpenAI model to use', optional: true
|
11
11
|
|
12
|
+
env :AI_AGENT_MAX_TOKENS, 'Max tokens for AI requests (For OpenAI Models, the default value is automatically decided)', optional: true
|
13
|
+
env :AI_AGENT_AUTO_COMPACT_THRESHOLD, 'Threshold of token usage in percentage to auto compact AI memory (default: 90)', optional: true
|
14
|
+
|
12
15
|
on(
|
13
16
|
/(?<body>.+)/m,
|
14
17
|
description: 'AI responds to your message if given message did not match any other handlers',
|
@@ -40,7 +40,7 @@ require 'fileutils'
|
|
40
40
|
# Generate RBS instance variable definitions for memorized methods
|
41
41
|
class MemorizedIvarRbsGenerator
|
42
42
|
Source = Data.define(:file, :content, :prism_node)
|
43
|
-
MemorizedMethod = Data.define(:class_name, :method_name, :ivar_name, :return_type, :file)
|
43
|
+
MemorizedMethod = Data.define(:class_name, :method_name, :ivar_name, :return_type, :file, :is_class_ivar)
|
44
44
|
|
45
45
|
def initialize(lib_path: 'lib', output_path: 'sig/generated-by-scripts', namespace_filter: nil)
|
46
46
|
@lib_path = Pathname(lib_path)
|
@@ -58,7 +58,8 @@ class MemorizedIvarRbsGenerator
|
|
58
58
|
|
59
59
|
puts "Found #{memorized_methods.size} memorized methods:"
|
60
60
|
memorized_methods.each do |method|
|
61
|
-
|
61
|
+
prefix = method.is_class_ivar ? '.' : '#'
|
62
|
+
puts " - #{method.class_name}#{prefix}#{method.method_name} -> @#{method.ivar_name}: #{method.return_type}"
|
62
63
|
end
|
63
64
|
|
64
65
|
generate_rbs_files(memorized_methods)
|
@@ -108,10 +109,20 @@ class MemorizedIvarRbsGenerator
|
|
108
109
|
# Class declaration with instance variables
|
109
110
|
content << ((' ' * indent_level) + "class #{parts.last}")
|
110
111
|
|
111
|
-
|
112
|
+
# Separate instance variables and class instance variables
|
113
|
+
instance_methods = methods.reject(&:is_class_ivar)
|
114
|
+
class_methods = methods.select(&:is_class_ivar)
|
115
|
+
|
116
|
+
# Add instance variables
|
117
|
+
instance_methods.each do |method|
|
112
118
|
content << ((' ' * (indent_level + 1)) + "@#{method.ivar_name}: #{method.return_type}")
|
113
119
|
end
|
114
120
|
|
121
|
+
# Add class instance variables (using self.@variable_name notation)
|
122
|
+
class_methods.each do |method|
|
123
|
+
content << ((' ' * (indent_level + 1)) + "self.@#{method.ivar_name}: #{method.return_type}")
|
124
|
+
end
|
125
|
+
|
115
126
|
content << "#{' ' * indent_level}end"
|
116
127
|
|
117
128
|
# Close namespaces
|
@@ -138,6 +149,7 @@ class MemorizedIvarRbsGenerator
|
|
138
149
|
@memorized_methods = []
|
139
150
|
@namespace = []
|
140
151
|
@current_class = nil
|
152
|
+
@in_singleton_class = false
|
141
153
|
super()
|
142
154
|
end
|
143
155
|
|
@@ -157,12 +169,22 @@ class MemorizedIvarRbsGenerator
|
|
157
169
|
end
|
158
170
|
end
|
159
171
|
|
172
|
+
def visit_singleton_class_node(node)
|
173
|
+
old_singleton = @in_singleton_class
|
174
|
+
@in_singleton_class = true
|
175
|
+
super
|
176
|
+
@in_singleton_class = old_singleton
|
177
|
+
end
|
178
|
+
|
160
179
|
def visit_def_node(node)
|
161
180
|
return unless @current_class
|
162
181
|
|
163
182
|
# Skip if namespace filter is set and doesn't match
|
164
183
|
return if @namespace_filter && !@current_class.start_with?(@namespace_filter)
|
165
184
|
|
185
|
+
# Check if it's a class method (def self.method_name)
|
186
|
+
is_class_method = node.receiver&.is_a?(Prism::SelfNode)
|
187
|
+
|
166
188
|
# Check for memorized annotation
|
167
189
|
if memorized_annotated?(node)
|
168
190
|
method_name = node.name.to_s
|
@@ -176,7 +198,8 @@ class MemorizedIvarRbsGenerator
|
|
176
198
|
method_name: method_name,
|
177
199
|
ivar_name: ivar_info[:ivar_name],
|
178
200
|
return_type: ivar_info[:return_type],
|
179
|
-
file: source.file
|
201
|
+
file: source.file,
|
202
|
+
is_class_ivar: @in_singleton_class || is_class_method
|
180
203
|
)
|
181
204
|
end
|
182
205
|
end
|
@@ -21,6 +21,10 @@ module Ruboty
|
|
21
21
|
# @rbs body: String
|
22
22
|
# @rbs return: void
|
23
23
|
def complete_chat: (String body) -> void
|
24
|
+
|
25
|
+
def truncate: (untyped text, max: untyped) -> untyped
|
26
|
+
|
27
|
+
def indent_with_quotation: (untyped text, ?untyped quota) -> untyped
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -7,11 +7,12 @@ module Ruboty
|
|
7
7
|
# @rbs message: ChatMessage
|
8
8
|
def add: (ChatMessage message) -> void
|
9
9
|
|
10
|
+
def token_usage: () -> TokenUsage?
|
11
|
+
|
10
12
|
alias << add
|
11
13
|
|
12
14
|
# Check if any message's token usage exceeds auto compact threshold
|
13
|
-
|
14
|
-
def over_auto_compact_threshold?: () -> bool
|
15
|
+
def over_auto_compact_threshold?: () -> boolish
|
15
16
|
|
16
17
|
# Compact chat messages by summarizing them
|
17
18
|
# @rbs llm: LLM::OpenAI
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Generated from lib/ruboty/ai_agent/settings.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Ruboty
|
4
|
+
module AiAgent
|
5
|
+
# Provide library-wide settings.
|
6
|
+
class Settings
|
7
|
+
# Provide access to settings instance.
|
8
|
+
module Accessor
|
9
|
+
def settings: () -> Ruboty::AiAgent::Settings
|
10
|
+
end
|
11
|
+
|
12
|
+
# @rbs %a{memorized}
|
13
|
+
%a{memorized}
|
14
|
+
def self.instance: () -> Ruboty::AiAgent::Settings
|
15
|
+
|
16
|
+
def max_tokens: () -> Integer?
|
17
|
+
|
18
|
+
def auto_compact_threshold: () -> Float
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generated from lib/ruboty/ai_agent/tool_definitions/bot_help.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Ruboty
|
4
|
+
module AiAgent
|
5
|
+
module ToolDefinitions
|
6
|
+
# Tool for retrieving Ruboty help information
|
7
|
+
class BotHelp < Base
|
8
|
+
# @rbs arguments: Hash[String, untyped]
|
9
|
+
# @rbs return: String?
|
10
|
+
def call: (Hash[String, untyped] arguments) -> String?
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# @rbs filter: String?
|
15
|
+
# @rbs return: Array[String]
|
16
|
+
def filtered_descriptions: (String? filter) -> Array[String]
|
17
|
+
|
18
|
+
# @rbs return: Array[String]
|
19
|
+
def all_descriptions: () -> Array[String]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Generated from lib/ruboty/ai_agent/tool_definitions/fetch.rb with RBS::Inline
|
2
|
+
|
3
|
+
module Ruboty
|
4
|
+
module AiAgent
|
5
|
+
module ToolDefinitions
|
6
|
+
# Fetch and extract readable content from web pages using ruby-readability
|
7
|
+
class Fetch < Base
|
8
|
+
class FetchError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
@available: bool
|
12
|
+
|
13
|
+
def self.avaliable!: () -> untyped
|
14
|
+
|
15
|
+
def self.not_avaliable!: () -> untyped
|
16
|
+
|
17
|
+
def self.available?: () -> boolish
|
18
|
+
|
19
|
+
# @rbs arguments: Hash[String, untyped]
|
20
|
+
# @rbs return: String?
|
21
|
+
def call: (Hash[String, untyped] arguments) -> String?
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# @rbs url: String
|
26
|
+
# @rbs return: String
|
27
|
+
def normalize_url: (String url) -> String
|
28
|
+
|
29
|
+
# @rbs url: String
|
30
|
+
# @rbs return: bool
|
31
|
+
def valid_url?: (String url) -> bool
|
32
|
+
|
33
|
+
# @rbs url: String
|
34
|
+
# @rbs return: String
|
35
|
+
def fetch_content: (String url) -> String
|
36
|
+
|
37
|
+
# @rbs content: String
|
38
|
+
# @rbs return: String
|
39
|
+
def extract_readable_content: (String content) -> String
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruboty-ai_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomoya Chiba
|
@@ -114,10 +114,13 @@ files:
|
|
114
114
|
- lib/ruboty/ai_agent/record_set.rb
|
115
115
|
- lib/ruboty/ai_agent/recordable.rb
|
116
116
|
- lib/ruboty/ai_agent/request.rb
|
117
|
+
- lib/ruboty/ai_agent/settings.rb
|
117
118
|
- lib/ruboty/ai_agent/token_usage.rb
|
118
119
|
- lib/ruboty/ai_agent/tool.rb
|
119
120
|
- lib/ruboty/ai_agent/tool_definitions.rb
|
120
121
|
- lib/ruboty/ai_agent/tool_definitions/base.rb
|
122
|
+
- lib/ruboty/ai_agent/tool_definitions/bot_help.rb
|
123
|
+
- lib/ruboty/ai_agent/tool_definitions/fetch.rb
|
121
124
|
- lib/ruboty/ai_agent/tool_definitions/think.rb
|
122
125
|
- lib/ruboty/ai_agent/user.rb
|
123
126
|
- lib/ruboty/ai_agent/user_ai_memories.rb
|
@@ -182,10 +185,13 @@ files:
|
|
182
185
|
- sig/generated/ruboty/ai_agent/record_set.rbs
|
183
186
|
- sig/generated/ruboty/ai_agent/recordable.rbs
|
184
187
|
- sig/generated/ruboty/ai_agent/request.rbs
|
188
|
+
- sig/generated/ruboty/ai_agent/settings.rbs
|
185
189
|
- sig/generated/ruboty/ai_agent/token_usage.rbs
|
186
190
|
- sig/generated/ruboty/ai_agent/tool.rbs
|
187
191
|
- sig/generated/ruboty/ai_agent/tool_definitions.rbs
|
188
192
|
- sig/generated/ruboty/ai_agent/tool_definitions/base.rbs
|
193
|
+
- sig/generated/ruboty/ai_agent/tool_definitions/bot_help.rbs
|
194
|
+
- sig/generated/ruboty/ai_agent/tool_definitions/fetch.rbs
|
189
195
|
- sig/generated/ruboty/ai_agent/tool_definitions/think.rbs
|
190
196
|
- sig/generated/ruboty/ai_agent/user.rbs
|
191
197
|
- sig/generated/ruboty/ai_agent/user_ai_memories.rbs
|