pocketrb 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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +98 -17
  4. data/lib/pocketrb/agent/compaction.rb +235 -22
  5. data/lib/pocketrb/agent/context.rb +26 -3
  6. data/lib/pocketrb/agent/loop.rb +53 -5
  7. data/lib/pocketrb/agent/spawn_tool.rb +14 -0
  8. data/lib/pocketrb/agent/subagent_manager.rb +24 -2
  9. data/lib/pocketrb/bus/events.rb +42 -1
  10. data/lib/pocketrb/bus/message_bus.rb +37 -0
  11. data/lib/pocketrb/channels/base.rb +13 -0
  12. data/lib/pocketrb/channels/cli.rb +16 -1
  13. data/lib/pocketrb/channels/telegram.rb +70 -4
  14. data/lib/pocketrb/channels/whatsapp.rb +49 -7
  15. data/lib/pocketrb/cli/chat.rb +7 -0
  16. data/lib/pocketrb/cli/config.rb +4 -0
  17. data/lib/pocketrb/cli/cron.rb +6 -0
  18. data/lib/pocketrb/cli.rb +0 -1
  19. data/lib/pocketrb/config.rb +55 -6
  20. data/lib/pocketrb/cron/job.rb +41 -0
  21. data/lib/pocketrb/cron/service.rb +44 -15
  22. data/lib/pocketrb/heartbeat/service.rb +21 -0
  23. data/lib/pocketrb/mcp/client.rb +41 -3
  24. data/lib/pocketrb/mcp/memory_tool.rb +33 -0
  25. data/lib/pocketrb/media/processor.rb +32 -1
  26. data/lib/pocketrb/memory.rb +12 -3
  27. data/lib/pocketrb/planning/manager.rb +29 -1
  28. data/lib/pocketrb/planning/plan.rb +52 -0
  29. data/lib/pocketrb/planning/tool.rb +45 -0
  30. data/lib/pocketrb/providers/anthropic.rb +113 -9
  31. data/lib/pocketrb/providers/base.rb +39 -4
  32. data/lib/pocketrb/providers/claude_cli.rb +79 -7
  33. data/lib/pocketrb/providers/claude_max_proxy.rb +72 -6
  34. data/lib/pocketrb/providers/openai_compatible.rb +79 -0
  35. data/lib/pocketrb/providers/openrouter.rb +72 -12
  36. data/lib/pocketrb/providers/registry.rb +24 -0
  37. data/lib/pocketrb/providers/ruby_llm_provider.rb +168 -54
  38. data/lib/pocketrb/providers/types.rb +51 -1
  39. data/lib/pocketrb/session/manager.rb +34 -2
  40. data/lib/pocketrb/session/session.rb +53 -11
  41. data/lib/pocketrb/skills/builtin/tmux/SKILL.md +9 -9
  42. data/lib/pocketrb/skills/create_tool.rb +28 -0
  43. data/lib/pocketrb/skills/loader.rb +22 -1
  44. data/lib/pocketrb/skills/modify_tool.rb +22 -0
  45. data/lib/pocketrb/skills/skill.rb +19 -3
  46. data/lib/pocketrb/tools/background_job_manager.rb +29 -0
  47. data/lib/pocketrb/tools/base.rb +16 -1
  48. data/lib/pocketrb/tools/browser.rb +40 -0
  49. data/lib/pocketrb/tools/browser_advanced.rb +94 -4
  50. data/lib/pocketrb/tools/browser_session.rb +18 -0
  51. data/lib/pocketrb/tools/cron.rb +46 -0
  52. data/lib/pocketrb/tools/edit_file.rb +16 -0
  53. data/lib/pocketrb/tools/exec.rb +46 -0
  54. data/lib/pocketrb/tools/jobs.rb +26 -2
  55. data/lib/pocketrb/tools/list_dir.rb +19 -0
  56. data/lib/pocketrb/tools/memory.rb +34 -0
  57. data/lib/pocketrb/tools/message.rb +15 -0
  58. data/lib/pocketrb/tools/para_memory.rb +47 -0
  59. data/lib/pocketrb/tools/read_file.rb +11 -0
  60. data/lib/pocketrb/tools/registry.rb +12 -4
  61. data/lib/pocketrb/tools/send_file.rb +29 -0
  62. data/lib/pocketrb/tools/think.rb +9 -0
  63. data/lib/pocketrb/tools/web_fetch.rb +58 -3
  64. data/lib/pocketrb/tools/web_search.rb +25 -0
  65. data/lib/pocketrb/tools/write_file.rb +10 -0
  66. data/lib/pocketrb/version.rb +2 -1
  67. data/lib/pocketrb.rb +4 -1
  68. data/pocketrb.gemspec +6 -8
  69. metadata +24 -44
@@ -4,6 +4,7 @@ module Pocketrb
4
4
  module Tools
5
5
  # Tool for sending files/images to chat channels
6
6
  class SendFile < Base
7
+ # Allowed file extensions for sending
7
8
  ALLOWED_EXTENSIONS = %w[
8
9
  .jpg .jpeg .png .gif .webp .bmp
9
10
  .pdf .txt .md .json .csv .xml
@@ -12,14 +13,20 @@ module Pocketrb
12
13
  .zip .tar .gz
13
14
  ].freeze
14
15
 
16
+ # Tool name
17
+ # @return [String]
15
18
  def name
16
19
  "send_file"
17
20
  end
18
21
 
22
+ # Tool description
23
+ # @return [String]
19
24
  def description
20
25
  "Send a file (image, document, audio, video) to the user via chat. Use this to share generated content, screenshots, reports, or any files."
21
26
  end
22
27
 
28
+ # Parameter schema
29
+ # @return [Hash]
23
30
  def parameters
24
31
  {
25
32
  type: "object",
@@ -45,6 +52,12 @@ module Pocketrb
45
52
  }
46
53
  end
47
54
 
55
+ # Execute file sending
56
+ # @param path [String] File path to send
57
+ # @param caption [String, nil] Optional caption text
58
+ # @param channel [String, nil] Target channel name
59
+ # @param chat_id [String, nil] Target chat identifier
60
+ # @return [String] Success or error message
48
61
  def execute(path:, caption: nil, channel: nil, chat_id: nil)
49
62
  # Resolve path
50
63
  file_path = resolve_path(path)
@@ -84,22 +97,32 @@ module Pocketrb
84
97
  success("Sent #{File.basename(file_path)} to #{channel}")
85
98
  end
86
99
 
100
+ # Check if tool is available
101
+ # @return [Boolean] true if message bus is available
87
102
  def available?
88
103
  !bus.nil?
89
104
  end
90
105
 
91
106
  private
92
107
 
108
+ # Access the message bus from context
109
+ # @return [Object, nil]
93
110
  def bus
94
111
  @context[:bus]
95
112
  end
96
113
 
114
+ # Resolve a path, using workspace as base for relative paths
115
+ # @param path [String] file path to resolve
116
+ # @return [String] absolute file path
97
117
  def resolve_path(path)
98
118
  return path if Pathname.new(path).absolute?
99
119
 
100
120
  workspace.join(path).to_s
101
121
  end
102
122
 
123
+ # Create a media object from a file path
124
+ # @param path [String] path to the file
125
+ # @return [Bus::Media] media object for sending
103
126
  def create_media(path)
104
127
  ext = File.extname(path).downcase
105
128
  mime_type = detect_mime_type(ext)
@@ -114,6 +137,9 @@ module Pocketrb
114
137
  )
115
138
  end
116
139
 
140
+ # Detect media type from file extension
141
+ # @param ext [String] file extension (e.g. ".png")
142
+ # @return [Symbol] media type (:image, :audio, :video, or :file)
117
143
  def detect_type(ext)
118
144
  case ext
119
145
  when ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"
@@ -127,6 +153,9 @@ module Pocketrb
127
153
  end
128
154
  end
129
155
 
156
+ # Detect MIME type from file extension
157
+ # @param ext [String] file extension (e.g. ".png")
158
+ # @return [String] MIME type string
130
159
  def detect_mime_type(ext)
131
160
  {
132
161
  ".jpg" => "image/jpeg",
@@ -4,14 +4,20 @@ module Pocketrb
4
4
  module Tools
5
5
  # Internal reasoning tool for complex problem solving
6
6
  class Think < Base
7
+ # Tool name
8
+ # @return [String]
7
9
  def name
8
10
  "think"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String]
11
15
  def description
12
16
  "Use this tool to think through complex problems step by step. The content is not shown to the user but helps you reason through the task. Use it when you need to analyze information, plan an approach, or work through logic."
13
17
  end
14
18
 
19
+ # Parameter schema
20
+ # @return [Hash]
15
21
  def parameters
16
22
  {
17
23
  type: "object",
@@ -25,6 +31,9 @@ module Pocketrb
25
31
  }
26
32
  end
27
33
 
34
+ # Execute thinking process
35
+ # @param thought [String] Internal reasoning or analysis text
36
+ # @return [String] Confirmation message
28
37
  def execute(thought:)
29
38
  # The thought is logged but not displayed to the user
30
39
  Pocketrb.logger.debug("Agent thought: #{thought[0..200]}...")
@@ -11,14 +11,20 @@ module Pocketrb
11
11
  MAX_CONTENT_SIZE = 500_000 # characters
12
12
  TIMEOUT = 30 # seconds
13
13
 
14
+ # Tool name
15
+ # @return [String]
14
16
  def name
15
17
  "web_fetch"
16
18
  end
17
19
 
20
+ # Tool description
21
+ # @return [String]
18
22
  def description
19
23
  "Fetch content from a URL. Returns the text content of the page. Use for reading documentation, articles, or other web content."
20
24
  end
21
25
 
26
+ # Parameter schema
27
+ # @return [Hash]
22
28
  def parameters
23
29
  {
24
30
  type: "object",
@@ -36,6 +42,10 @@ module Pocketrb
36
42
  }
37
43
  end
38
44
 
45
+ # Execute web content fetching
46
+ # @param url [String] URL to fetch content from
47
+ # @param selector [String, nil] CSS selector for extracting specific content
48
+ # @return [String] Extracted text content or error message
39
49
  def execute(url:, selector: nil)
40
50
  # Validate URL
41
51
  uri = parse_url(url)
@@ -54,6 +64,9 @@ module Pocketrb
54
64
 
55
65
  private
56
66
 
67
+ # Parse and validate a URL, adding https if no scheme is present
68
+ # @param url [String] URL string to parse
69
+ # @return [URI, nil] parsed URI or nil if invalid
57
70
  def parse_url(url)
58
71
  # Add https if no scheme
59
72
  url = "https://#{url}" unless url.match?(%r{^https?://})
@@ -66,6 +79,9 @@ module Pocketrb
66
79
  nil
67
80
  end
68
81
 
82
+ # Fetch content from a URI using Faraday
83
+ # @param uri [URI] parsed URI to fetch
84
+ # @return [Hash] response hash with :body/:content_type or :error
69
85
  def fetch_url(uri)
70
86
  conn = Faraday.new(url: uri.to_s) do |f|
71
87
  f.options.timeout = TIMEOUT
@@ -79,12 +95,35 @@ module Pocketrb
79
95
  response = conn.get
80
96
 
81
97
  if response.success?
82
- { body: response.body, content_type: response.headers["content-type"] }
98
+ content_type = response.headers["content-type"]
99
+ { body: to_utf8(response.body.to_s, content_type), content_type: content_type }
83
100
  else
84
101
  { error: "HTTP #{response.status}" }
85
102
  end
86
103
  end
87
104
 
105
+ # Convert a raw response body to valid UTF-8
106
+ # @param body [String] raw response body
107
+ # @param content_type [String, nil] Content-Type header value
108
+ # @return [String] UTF-8 body with invalid bytes replaced
109
+ def to_utf8(body, content_type)
110
+ charset = content_type.to_s[/charset=["']?([^;"'\s]+)/i, 1]
111
+ encoding = begin
112
+ charset ? Encoding.find(charset) : Encoding::UTF_8
113
+ rescue ArgumentError
114
+ Encoding::UTF_8
115
+ end
116
+
117
+ body
118
+ .dup
119
+ .force_encoding(encoding)
120
+ .encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
121
+ end
122
+
123
+ # Extract readable content from response body
124
+ # @param body [String] raw response body
125
+ # @param selector [String, nil] CSS selector to narrow extraction
126
+ # @return [String] extracted text content
88
127
  def extract_content(body, selector)
89
128
  content_type = detect_content_type(body)
90
129
 
@@ -98,6 +137,9 @@ module Pocketrb
98
137
  end
99
138
  end
100
139
 
140
+ # Detect content type by inspecting the body
141
+ # @param body [String] response body to analyze
142
+ # @return [Symbol] :json, :html, or :text
101
143
  def detect_content_type(body)
102
144
  return :json if body.strip.start_with?("{", "[")
103
145
  return :html if body.include?("<html") || body.include?("<body")
@@ -105,6 +147,10 @@ module Pocketrb
105
147
  :text
106
148
  end
107
149
 
150
+ # Convert HTML to plain text by stripping tags
151
+ # @param html [String] raw HTML content
152
+ # @param _selector [String, nil] CSS selector (unused, reserved for Nokogiri)
153
+ # @return [String] extracted plain text
108
154
  def extract_html_content(html, _selector)
109
155
  # Simple HTML to text conversion
110
156
  # A full implementation would use nokogiri
@@ -120,11 +166,14 @@ module Pocketrb
120
166
  .gsub("&lt;", "<")
121
167
  .gsub("&gt;", ">")
122
168
  .gsub("&quot;", '"')
123
- .gsub(/&#\d+;/) do |m|
124
- [m[2..].to_i].pack("U")
169
+
170
+ text = text.gsub(/&#\d+;/) do |m|
171
+ [m[2..].to_i].pack("U")
125
172
  rescue StandardError
126
173
  m
127
174
  end
175
+
176
+ text = text
128
177
  .gsub(/\n{3,}/, "\n\n")
129
178
  .strip
130
179
 
@@ -132,6 +181,9 @@ module Pocketrb
132
181
  text.lines.map(&:strip).reject(&:empty?).join("\n")
133
182
  end
134
183
 
184
+ # Pretty-print JSON body
185
+ # @param body [String] raw JSON string
186
+ # @return [String] formatted JSON or original body on parse error
135
187
  def format_json(body)
136
188
  data = JSON.parse(body)
137
189
  JSON.pretty_generate(data)
@@ -139,6 +191,9 @@ module Pocketrb
139
191
  body
140
192
  end
141
193
 
194
+ # Truncate content exceeding the maximum size
195
+ # @param content [String] extracted page text that may exceed size limits
196
+ # @return [String] truncated or original content
142
197
  def truncate_content(content)
143
198
  return content if content.length <= MAX_CONTENT_SIZE
144
199
 
@@ -7,16 +7,23 @@ module Pocketrb
7
7
  module Tools
8
8
  # Search the web using Brave Search API
9
9
  class WebSearch < Base
10
+ # Brave Search API endpoint URL
10
11
  BRAVE_API_URL = "https://api.search.brave.com/res/v1/web/search"
11
12
 
13
+ # Tool name
14
+ # @return [String]
12
15
  def name
13
16
  "web_search"
14
17
  end
15
18
 
19
+ # Tool description
20
+ # @return [String]
16
21
  def description
17
22
  "Search the web for information. Returns relevant search results with titles, URLs, and descriptions."
18
23
  end
19
24
 
25
+ # Parameter schema
26
+ # @return [Hash]
20
27
  def parameters
21
28
  {
22
29
  type: "object",
@@ -34,10 +41,16 @@ module Pocketrb
34
41
  }
35
42
  end
36
43
 
44
+ # Check if tool is available
45
+ # @return [Boolean] true if Brave API key is configured
37
46
  def available?
38
47
  api_key && !api_key.empty?
39
48
  end
40
49
 
50
+ # Execute web search
51
+ # @param query [String] Search query string
52
+ # @param count [Integer] Number of results to return (1-20)
53
+ # @return [String] Formatted search results
41
54
  def execute(query:, count: 5)
42
55
  return error("Web search requires BRAVE_API_KEY environment variable") unless api_key
43
56
 
@@ -60,10 +73,14 @@ module Pocketrb
60
73
 
61
74
  private
62
75
 
76
+ # Get the Brave Search API key from context or environment
77
+ # @return [String, nil]
63
78
  def api_key
64
79
  @context[:brave_api_key] || ENV.fetch("BRAVE_API_KEY", nil)
65
80
  end
66
81
 
82
+ # Build or access the Faraday HTTP client for Brave API
83
+ # @return [Faraday::Connection]
67
84
  def client
68
85
  @client ||= Faraday.new(url: BRAVE_API_URL) do |f|
69
86
  f.headers["Accept"] = "application/json"
@@ -72,6 +89,10 @@ module Pocketrb
72
89
  end
73
90
  end
74
91
 
92
+ # Format search response data into readable output
93
+ # @param data [Hash] parsed JSON response from Brave API
94
+ # @param query [String] original search query
95
+ # @return [String] formatted search results
75
96
  def format_results(data, query)
76
97
  results = data.dig("web", "results") || []
77
98
 
@@ -86,6 +107,10 @@ module Pocketrb
86
107
  output.join("\n")
87
108
  end
88
109
 
110
+ # Format a single search result entry
111
+ # @param result [Hash] search result with title, url, and description
112
+ # @param index [Integer] result number for display
113
+ # @return [String] formatted result entry
89
114
  def format_result(result, index)
90
115
  title = result["title"] || "Untitled"
91
116
  url = result["url"] || ""
@@ -6,14 +6,20 @@ module Pocketrb
6
6
  class WriteFile < Base
7
7
  MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
8
8
 
9
+ # Tool name
10
+ # @return [String]
9
11
  def name
10
12
  "write_file"
11
13
  end
12
14
 
15
+ # Tool description
16
+ # @return [String]
13
17
  def description
14
18
  "Write content to a file. Creates the file if it doesn't exist, or overwrites if it does. Creates parent directories as needed."
15
19
  end
16
20
 
21
+ # Parameter schema
22
+ # @return [Hash]
17
23
  def parameters
18
24
  {
19
25
  type: "object",
@@ -31,6 +37,10 @@ module Pocketrb
31
37
  }
32
38
  end
33
39
 
40
+ # Execute file write operation
41
+ # @param path [String] File path (relative or absolute)
42
+ # @param content [String] File content (text or binary data) to write to disk
43
+ # @return [String] Success or error message
34
44
  def execute(path:, content:)
35
45
  resolved = resolve_path(path)
36
46
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pocketrb
4
- VERSION = "0.1.0"
4
+ # Gem version number
5
+ VERSION = "0.3.0"
5
6
  end
data/lib/pocketrb.rb CHANGED
@@ -6,7 +6,6 @@ require "json"
6
6
  require "yaml"
7
7
  require "logger"
8
8
  require "fileutils"
9
- require "pathname"
10
9
 
11
10
  # Pocketrb: Ruby AI agent with multi-LLM support and advanced planning capabilities
12
11
  module Pocketrb
@@ -28,6 +27,9 @@ module Pocketrb
28
27
  # Raised when MCP (Model Context Protocol) operations fail
29
28
  class MCPError < Error; end
30
29
 
30
+ # Raised when an optional gem needed by a feature is not installed
31
+ class MissingDependencyError < LoadError; end
32
+
31
33
  class << self
32
34
  attr_writer :logger
33
35
 
@@ -54,6 +56,7 @@ loader.inflector.inflect(
54
56
  "llm" => "LLM",
55
57
  "mcp" => "MCP",
56
58
  "openrouter" => "OpenRouter",
59
+ "openai_compatible" => "OpenAICompatible",
57
60
  "ruby_llm_provider" => "RubyLLMProvider",
58
61
  "claude_cli" => "ClaudeCLI",
59
62
  "claude_max_proxy" => "ClaudeMaxProxy",
data/pocketrb.gemspec CHANGED
@@ -21,21 +21,19 @@ Gem::Specification.new do |spec|
21
21
  JSON-based memory with keyword matching.
22
22
  DESC
23
23
 
24
- spec.required_ruby_version = ">= 3.2.0"
24
+ spec.required_ruby_version = ">= 4.0.0"
25
25
 
26
26
  # Runtime dependencies
27
- spec.add_dependency "anthropic", "~> 0.3"
28
27
  spec.add_dependency "async", "~> 2.0"
29
28
  spec.add_dependency "faraday", "~> 2.0"
30
29
  spec.add_dependency "faraday-follow_redirects", "~> 0.3"
31
- spec.add_dependency "json", "~> 2.7"
32
- spec.add_dependency "pastel", "~> 0.8"
30
+ spec.add_dependency "fugit", "~> 1.11"
31
+ spec.add_dependency "json", ">= 2.7", "< 4"
33
32
  spec.add_dependency "playwright-ruby-client", "~> 1.58"
34
- spec.add_dependency "ruby_llm", "~> 1.0"
33
+ spec.add_dependency "ruby_llm", "~> 2.0"
35
34
  spec.add_dependency "telegram-bot-ruby", "~> 2.0"
36
35
  spec.add_dependency "thor", "~> 1.3"
37
- spec.add_dependency "tty-markdown", "~> 0.7"
38
- spec.add_dependency "tty-prompt", "~> 0.23"
36
+ spec.add_dependency "tty-spinner", "~> 0.9"
39
37
  spec.add_dependency "yaml", "~> 0.3"
40
38
  spec.add_dependency "zeitwerk", "~> 2.6"
41
39
 
@@ -51,10 +49,10 @@ Gem::Specification.new do |spec|
51
49
  "changelog_uri" => "https://github.com/mensfeld/pocketrb/blob/master/CHANGELOG.md",
52
50
  "homepage_uri" => "https://github.com/mensfeld/pocketrb",
53
51
  "source_code_uri" => "https://github.com/mensfeld/pocketrb/tree/master",
52
+ "documentation_uri" => "https://github.com/mensfeld/pocketrb",
54
53
  "rubygems_mfa_required" => "true"
55
54
  }
56
55
  end
57
56
 
58
57
  # Optional dependencies (loaded on demand)
59
58
  # For WhatsApp bridge: gem install websocket-client-simple
60
- # For cron expressions: gem install fugit
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pocketrb
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
  - Maciej Mensfeld
@@ -9,20 +9,6 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: anthropic
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '0.3'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '0.3'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: async
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -66,33 +52,39 @@ dependencies:
66
52
  - !ruby/object:Gem::Version
67
53
  version: '0.3'
68
54
  - !ruby/object:Gem::Dependency
69
- name: json
55
+ name: fugit
70
56
  requirement: !ruby/object:Gem::Requirement
71
57
  requirements:
72
58
  - - "~>"
73
59
  - !ruby/object:Gem::Version
74
- version: '2.7'
60
+ version: '1.11'
75
61
  type: :runtime
76
62
  prerelease: false
77
63
  version_requirements: !ruby/object:Gem::Requirement
78
64
  requirements:
79
65
  - - "~>"
80
66
  - !ruby/object:Gem::Version
81
- version: '2.7'
67
+ version: '1.11'
82
68
  - !ruby/object:Gem::Dependency
83
- name: pastel
69
+ name: json
84
70
  requirement: !ruby/object:Gem::Requirement
85
71
  requirements:
86
- - - "~>"
72
+ - - ">="
87
73
  - !ruby/object:Gem::Version
88
- version: '0.8'
74
+ version: '2.7'
75
+ - - "<"
76
+ - !ruby/object:Gem::Version
77
+ version: '4'
89
78
  type: :runtime
90
79
  prerelease: false
91
80
  version_requirements: !ruby/object:Gem::Requirement
92
81
  requirements:
93
- - - "~>"
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '2.7'
85
+ - - "<"
94
86
  - !ruby/object:Gem::Version
95
- version: '0.8'
87
+ version: '4'
96
88
  - !ruby/object:Gem::Dependency
97
89
  name: playwright-ruby-client
98
90
  requirement: !ruby/object:Gem::Requirement
@@ -113,14 +105,14 @@ dependencies:
113
105
  requirements:
114
106
  - - "~>"
115
107
  - !ruby/object:Gem::Version
116
- version: '1.0'
108
+ version: '2.0'
117
109
  type: :runtime
118
110
  prerelease: false
119
111
  version_requirements: !ruby/object:Gem::Requirement
120
112
  requirements:
121
113
  - - "~>"
122
114
  - !ruby/object:Gem::Version
123
- version: '1.0'
115
+ version: '2.0'
124
116
  - !ruby/object:Gem::Dependency
125
117
  name: telegram-bot-ruby
126
118
  requirement: !ruby/object:Gem::Requirement
@@ -150,33 +142,19 @@ dependencies:
150
142
  - !ruby/object:Gem::Version
151
143
  version: '1.3'
152
144
  - !ruby/object:Gem::Dependency
153
- name: tty-markdown
154
- requirement: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - "~>"
157
- - !ruby/object:Gem::Version
158
- version: '0.7'
159
- type: :runtime
160
- prerelease: false
161
- version_requirements: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - "~>"
164
- - !ruby/object:Gem::Version
165
- version: '0.7'
166
- - !ruby/object:Gem::Dependency
167
- name: tty-prompt
145
+ name: tty-spinner
168
146
  requirement: !ruby/object:Gem::Requirement
169
147
  requirements:
170
148
  - - "~>"
171
149
  - !ruby/object:Gem::Version
172
- version: '0.23'
150
+ version: '0.9'
173
151
  type: :runtime
174
152
  prerelease: false
175
153
  version_requirements: !ruby/object:Gem::Requirement
176
154
  requirements:
177
155
  - - "~>"
178
156
  - !ruby/object:Gem::Version
179
- version: '0.23'
157
+ version: '0.9'
180
158
  - !ruby/object:Gem::Dependency
181
159
  name: yaml
182
160
  requirement: !ruby/object:Gem::Requirement
@@ -261,6 +239,7 @@ files:
261
239
  - lib/pocketrb/providers/base.rb
262
240
  - lib/pocketrb/providers/claude_cli.rb
263
241
  - lib/pocketrb/providers/claude_max_proxy.rb
242
+ - lib/pocketrb/providers/openai_compatible.rb
264
243
  - lib/pocketrb/providers/openrouter.rb
265
244
  - lib/pocketrb/providers/registry.rb
266
245
  - lib/pocketrb/providers/ruby_llm_provider.rb
@@ -306,6 +285,7 @@ metadata:
306
285
  changelog_uri: https://github.com/mensfeld/pocketrb/blob/master/CHANGELOG.md
307
286
  homepage_uri: https://github.com/mensfeld/pocketrb
308
287
  source_code_uri: https://github.com/mensfeld/pocketrb/tree/master
288
+ documentation_uri: https://github.com/mensfeld/pocketrb
309
289
  rubygems_mfa_required: 'true'
310
290
  rdoc_options: []
311
291
  require_paths:
@@ -314,14 +294,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
314
294
  requirements:
315
295
  - - ">="
316
296
  - !ruby/object:Gem::Version
317
- version: 3.2.0
297
+ version: 4.0.0
318
298
  required_rubygems_version: !ruby/object:Gem::Requirement
319
299
  requirements:
320
300
  - - ">="
321
301
  - !ruby/object:Gem::Version
322
302
  version: '0'
323
303
  requirements: []
324
- rubygems_version: 4.0.0.beta2
304
+ rubygems_version: 4.0.20
325
305
  specification_version: 4
326
306
  summary: Pocket-sized Ruby AI agent framework with multi-LLM support
327
307
  test_files: []