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 @@ require "open3"
4
4
  require "timeout"
5
5
 
6
6
  module Pocketrb
7
+ # Tool implementations for agent capabilities
7
8
  module Tools
8
9
  # Execute shell commands with smart timeout and background job support
9
10
  class Exec < Base
@@ -14,7 +15,9 @@ module Pocketrb
14
15
  complex: 300 # Builds, installs
15
16
  }.freeze
16
17
 
18
+ # Default timeout for standard commands in seconds
17
19
  DEFAULT_TIMEOUT = TIMEOUTS[:standard]
20
+ # Maximum output size to capture in bytes
18
21
  MAX_OUTPUT_SIZE = 100_000
19
22
 
20
23
  # Quick commands that should finish fast
@@ -29,14 +32,20 @@ module Pocketrb
29
32
  /^\[/ # test bracket syntax
30
33
  ].freeze
31
34
 
35
+ # Tool name
36
+ # @return [String]
32
37
  def name
33
38
  "exec"
34
39
  end
35
40
 
41
+ # Tool description
42
+ # @return [String]
36
43
  def description
37
44
  "Execute a shell command. Long-running commands (apt install, npm install, etc.) auto-run in background. Use for git, npm, make, and other development tools."
38
45
  end
39
46
 
47
+ # Parameter schema
48
+ # @return [Hash]
40
49
  def parameters
41
50
  {
42
51
  type: "object",
@@ -62,6 +71,12 @@ module Pocketrb
62
71
  }
63
72
  end
64
73
 
74
+ # Execute shell command
75
+ # @param command [String] Shell command to execute
76
+ # @param timeout [Integer, nil] Execution timeout in seconds
77
+ # @param working_dir [String, nil] Working directory for command
78
+ # @param background [Boolean, nil] Force background execution
79
+ # @return [String] Command output or job information
65
80
  def execute(command:, timeout: nil, working_dir: nil, background: nil)
66
81
  work_dir = resolve_working_dir(working_dir)
67
82
  return work_dir if work_dir.is_a?(String) && work_dir.start_with?("Error:")
@@ -80,10 +95,15 @@ module Pocketrb
80
95
 
81
96
  private
82
97
 
98
+ # Access or initialize the background job manager
99
+ # @return [BackgroundJobManager]
83
100
  def job_manager
84
101
  @job_manager ||= BackgroundJobManager.new(workspace: workspace)
85
102
  end
86
103
 
104
+ # Resolve and validate the working directory
105
+ # @param working_dir [String, nil] explicit directory path or nil for workspace
106
+ # @return [String] resolved directory path or error string
87
107
  def resolve_working_dir(working_dir)
88
108
  if working_dir
89
109
  resolved = resolve_path(working_dir)
@@ -95,6 +115,10 @@ module Pocketrb
95
115
  end
96
116
  end
97
117
 
118
+ # Run a command as a background job
119
+ # @param command [String] shell command to run
120
+ # @param work_dir [String] working directory
121
+ # @return [String] job metadata including ID and PID
98
122
  def execute_background(command, work_dir)
99
123
  Pocketrb.logger.debug("Running in background: #{command}")
100
124
 
@@ -114,6 +138,11 @@ module Pocketrb
114
138
  OUTPUT
115
139
  end
116
140
 
141
+ # Run a command in the foreground with timeout
142
+ # @param command [String] shell command to run
143
+ # @param work_dir [String] working directory
144
+ # @param explicit_timeout [Integer, nil] timeout in seconds, auto-detected if nil
145
+ # @return [String] command output and exit status
117
146
  def execute_foreground(command, work_dir, explicit_timeout)
118
147
  timeout = explicit_timeout || smart_timeout(command)
119
148
  timeout = [timeout, 600].min if timeout
@@ -137,6 +166,9 @@ module Pocketrb
137
166
  format_result(stdout, stderr, status)
138
167
  end
139
168
 
169
+ # Determine timeout based on command type
170
+ # @param command [String] shell command to analyze
171
+ # @return [Integer, nil] timeout in seconds or nil for no timeout
140
172
  def smart_timeout(command)
141
173
  return TIMEOUTS[:simple] if quick_command?(command)
142
174
  return nil if job_manager.long_running?(command)
@@ -144,12 +176,18 @@ module Pocketrb
144
176
  TIMEOUTS[:standard]
145
177
  end
146
178
 
179
+ # Check if command matches fast-executing patterns
180
+ # @param command [String] shell command to check
181
+ # @return [Boolean]
147
182
  def quick_command?(command)
148
183
  return false if command.nil? || command.empty?
149
184
 
150
185
  QUICK_PATTERNS.any? { |p| command.match?(p) }
151
186
  end
152
187
 
188
+ # Check if command matches known dangerous patterns
189
+ # @param command [String] shell command to check
190
+ # @return [Boolean]
153
191
  def dangerous_command?(command)
154
192
  dangerous_patterns = [
155
193
  %r{\brm\s+-rf\s+[/~]},
@@ -165,6 +203,11 @@ module Pocketrb
165
203
  dangerous_patterns.any? { |pattern| command.match?(pattern) }
166
204
  end
167
205
 
206
+ # Format command execution result for display
207
+ # @param stdout [String] standard output
208
+ # @param stderr [String] standard error
209
+ # @param status [Process::Status] exit status
210
+ # @return [String] formatted result
168
211
  def format_result(stdout, stderr, status)
169
212
  output_parts = []
170
213
 
@@ -183,6 +226,9 @@ module Pocketrb
183
226
  output_parts.join("\n\n")
184
227
  end
185
228
 
229
+ # Truncate output that exceeds the maximum size
230
+ # @param output [String] output text to truncate
231
+ # @return [String] truncated or original output
186
232
  def truncate_output(output)
187
233
  return output if output.length <= MAX_OUTPUT_SIZE
188
234
 
@@ -4,14 +4,20 @@ module Pocketrb
4
4
  module Tools
5
5
  # Manage background jobs
6
6
  class Jobs < Base
7
+ # Tool name
8
+ # @return [String] Tool identifier
7
9
  def name
8
10
  "jobs"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String] Human-readable description
11
15
  def description
12
16
  "Manage background jobs. List running/completed jobs, get output, or kill jobs."
13
17
  end
14
18
 
19
+ # Tool parameters schema
20
+ # @return [Hash] JSON schema for tool parameters
15
21
  def parameters
16
22
  {
17
23
  type: "object",
@@ -34,6 +40,11 @@ module Pocketrb
34
40
  }
35
41
  end
36
42
 
43
+ # Execute background job operation
44
+ # @param action [String] Action to perform (list, status, output, kill)
45
+ # @param job_id [String, nil] Job identifier (for status/output/kill actions)
46
+ # @param lines [Integer] Number of output lines to show (defaults to 50)
47
+ # @return [String] JSON result of operation
37
48
  def execute(action:, job_id: nil, lines: 50)
38
49
  case action
39
50
  when "list"
@@ -51,12 +62,16 @@ module Pocketrb
51
62
 
52
63
  private
53
64
 
65
+ # Access or initialize the background job manager
66
+ # @return [BackgroundJobManager]
54
67
  def job_manager
55
68
  # Use memory_dir for job storage (falls back to workspace if not set)
56
69
  storage_dir = @context[:memory_dir] || workspace
57
70
  @job_manager ||= BackgroundJobManager.new(workspace: storage_dir)
58
71
  end
59
72
 
73
+ # List all background jobs grouped by running/completed status
74
+ # @return [String] formatted job listing
60
75
  def list_jobs
61
76
  jobs = job_manager.list
62
77
 
@@ -64,8 +79,7 @@ module Pocketrb
64
79
 
65
80
  output = ["Background Jobs:\n"]
66
81
 
67
- running = jobs.select { |j| j[:running] }
68
- completed = jobs.reject { |j| j[:running] }
82
+ running, completed = jobs.partition { |j| j[:running] }
69
83
 
70
84
  if running.any?
71
85
  output << "RUNNING:"
@@ -86,6 +100,9 @@ module Pocketrb
86
100
  output.join("\n")
87
101
  end
88
102
 
103
+ # Get detailed status of a job
104
+ # @param job_id [String] job identifier
105
+ # @return [String] job status details or error message
89
106
  def get_status(job_id)
90
107
  return error("Job ID required") unless job_id
91
108
 
@@ -104,6 +121,10 @@ module Pocketrb
104
121
  STATUS
105
122
  end
106
123
 
124
+ # Get recent output from a job
125
+ # @param job_id [String] job identifier
126
+ # @param lines [Integer] number of lines to retrieve
127
+ # @return [String] job output or error message
107
128
  def get_output(job_id, lines)
108
129
  return error("Job ID required") unless job_id
109
130
 
@@ -113,6 +134,9 @@ module Pocketrb
113
134
  "Output (last #{lines} lines):\n#{output}"
114
135
  end
115
136
 
137
+ # Kill a running job
138
+ # @param job_id [String] job identifier
139
+ # @return [String] confirmation or error message
116
140
  def kill_job(job_id)
117
141
  return error("Job ID required") unless job_id
118
142
 
@@ -4,14 +4,20 @@ module Pocketrb
4
4
  module Tools
5
5
  # List directory contents
6
6
  class ListDir < Base
7
+ # Tool name
8
+ # @return [String]
7
9
  def name
8
10
  "list_dir"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String]
11
15
  def description
12
16
  "List the contents of a directory. Shows files and subdirectories with basic metadata."
13
17
  end
14
18
 
19
+ # Parameter schema
20
+ # @return [Hash]
15
21
  def parameters
16
22
  {
17
23
  type: "object",
@@ -37,6 +43,12 @@ module Pocketrb
37
43
  }
38
44
  end
39
45
 
46
+ # Execute directory listing
47
+ # @param path [String, nil] Directory path to list (defaults to workspace root)
48
+ # @param pattern [String, nil] Glob pattern to filter results
49
+ # @param recursive [Boolean] Whether to list subdirectories recursively
50
+ # @param include_hidden [Boolean] Whether to include hidden files
51
+ # @return [String] Formatted directory listing
40
52
  def execute(path: nil, pattern: nil, recursive: false, include_hidden: false)
41
53
  resolved = path ? validate_path!(path) : workspace
42
54
 
@@ -73,6 +85,10 @@ module Pocketrb
73
85
 
74
86
  private
75
87
 
88
+ # Format a directory entry for display
89
+ # @param path [Pathname] absolute path to the entry
90
+ # @param relative [Pathname] path relative to workspace
91
+ # @return [String] formatted entry with metadata
76
92
  def format_entry(path, relative)
77
93
  if path.directory?
78
94
  "#{relative}/"
@@ -85,6 +101,9 @@ module Pocketrb
85
101
  relative.to_s
86
102
  end
87
103
 
104
+ # Format byte size into human-readable units
105
+ # @param bytes [Integer] size in bytes
106
+ # @return [String] formatted size string (e.g. "1.5KB")
88
107
  def format_size(bytes)
89
108
  units = %w[B KB MB GB]
90
109
  unit_index = 0
@@ -4,13 +4,19 @@ module Pocketrb
4
4
  module Tools
5
5
  # Simple memory tool - store and recall facts
6
6
  class Memory < Base
7
+ # Available memory actions
7
8
  ACTIONS = %w[store recall search recent stats].freeze
9
+ # Memory categories for organization
8
10
  CATEGORIES = %w[learned user preference context].freeze
9
11
 
12
+ # Tool name
13
+ # @return [String]
10
14
  def name
11
15
  "memory"
12
16
  end
13
17
 
18
+ # Tool description
19
+ # @return [String]
14
20
  def description
15
21
  <<~DESC.strip
16
22
  Store and recall memories. Use this to remember important facts, preferences, and learnings.
@@ -24,6 +30,8 @@ module Pocketrb
24
30
  DESC
25
31
  end
26
32
 
33
+ # Parameter schema
34
+ # @return [Hash]
27
35
  def parameters
28
36
  {
29
37
  type: "object",
@@ -55,10 +63,19 @@ module Pocketrb
55
63
  }
56
64
  end
57
65
 
66
+ # Check if tool is available
67
+ # @return [Boolean] true if memory system is initialized
58
68
  def available?
59
69
  !memory_instance.nil?
60
70
  end
61
71
 
72
+ # Execute memory action
73
+ # @param action [String] Action to perform (store, recall, search, recent, stats)
74
+ # @param category [String, nil] Category for storing memories
75
+ # @param key [String, nil] Memory key or topic
76
+ # @param value [String, nil] Memory content to store
77
+ # @param query [String, nil] Search query for recall/search
78
+ # @return [String] Action result or error message
62
79
  def execute(action:, category: nil, key: nil, value: nil, query: nil, **)
63
80
  return error("Memory not initialized") unless memory_instance
64
81
 
@@ -82,10 +99,17 @@ module Pocketrb
82
99
 
83
100
  private
84
101
 
102
+ # Access the memory system from context
103
+ # @return [Object, nil]
85
104
  def memory_instance
86
105
  @context[:memory]
87
106
  end
88
107
 
108
+ # Store a fact in the specified category
109
+ # @param category [String] memory category (learned, user, preference, context)
110
+ # @param key [String] memory key or topic
111
+ # @param value [String] content to store
112
+ # @return [String] confirmation or error message
89
113
  def store_memory(category, key, value)
90
114
  return error("Category, key, and value required") unless category && key && value
91
115
 
@@ -105,6 +129,9 @@ module Pocketrb
105
129
  success(result)
106
130
  end
107
131
 
132
+ # Recall relevant memories matching a query
133
+ # @param query [String] search query
134
+ # @return [String] matching memories or not-found message
108
135
  def recall_memory(query)
109
136
  return error("Query required") unless query
110
137
 
@@ -117,6 +144,9 @@ module Pocketrb
117
144
  end
118
145
  end
119
146
 
147
+ # Deep search across all memory categories
148
+ # @param query [String] search query
149
+ # @return [String] search results or not-found message
120
150
  def search_memory(query)
121
151
  return error("Query required") unless query
122
152
 
@@ -134,6 +164,8 @@ module Pocketrb
134
164
  lines.join("\n")
135
165
  end
136
166
 
167
+ # Show recent events from memory
168
+ # @return [String] formatted list of recent events
137
169
  def show_recent
138
170
  events = memory_instance.recent_events(10)
139
171
 
@@ -148,6 +180,8 @@ module Pocketrb
148
180
  lines.join("\n")
149
181
  end
150
182
 
183
+ # Show memory system statistics
184
+ # @return [String] formatted memory statistics
151
185
  def show_stats
152
186
  stats = memory_instance.stats
153
187
 
@@ -4,14 +4,20 @@ module Pocketrb
4
4
  module Tools
5
5
  # Tool for sending messages to chat channels programmatically
6
6
  class Message < Base
7
+ # Tool name
8
+ # @return [String]
7
9
  def name
8
10
  "message"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String]
11
15
  def description
12
16
  "Send a message to a chat channel. Use this to proactively communicate with users, send notifications, or respond on specific channels."
13
17
  end
14
18
 
19
+ # Parameter schema
20
+ # @return [Hash]
15
21
  def parameters
16
22
  {
17
23
  type: "object",
@@ -33,6 +39,11 @@ module Pocketrb
33
39
  }
34
40
  end
35
41
 
42
+ # Execute message sending
43
+ # @param content [String] Message text to send
44
+ # @param channel [String, nil] Target channel name
45
+ # @param chat_id [String, nil] Target chat identifier
46
+ # @return [String] Success or error message
36
47
  def execute(content:, channel: nil, chat_id: nil)
37
48
  # Use defaults from context if not provided
38
49
  channel = (channel || @context[:default_channel])&.to_sym
@@ -56,12 +67,16 @@ module Pocketrb
56
67
  success("Message sent to #{channel}:#{chat_id}")
57
68
  end
58
69
 
70
+ # Check if message bus is available
71
+ # @return [Boolean] True if bus is configured
59
72
  def available?
60
73
  !bus.nil?
61
74
  end
62
75
 
63
76
  private
64
77
 
78
+ # Access the message bus from context
79
+ # @return [Object, nil]
65
80
  def bus
66
81
  @context[:bus]
67
82
  end
@@ -4,10 +4,14 @@ module Pocketrb
4
4
  module Tools
5
5
  # PARA-based memory tool for structured knowledge management
6
6
  class ParaMemory < Base
7
+ # Tool name
8
+ # @return [String]
7
9
  def name
8
10
  "para_memory"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String]
11
15
  def description
12
16
  <<~DESC.strip
13
17
  Structured memory using PARA method. Store and retrieve facts about people, projects,
@@ -16,6 +20,8 @@ module Pocketrb
16
20
  DESC
17
21
  end
18
22
 
23
+ # Parameter schema
24
+ # @return [Hash]
19
25
  def parameters
20
26
  {
21
27
  type: "object",
@@ -74,10 +80,25 @@ module Pocketrb
74
80
  }
75
81
  end
76
82
 
83
+ # Check if tool is available
84
+ # @return [Boolean] true if PARA manager is configured
77
85
  def available?
78
86
  !para_manager.nil?
79
87
  end
80
88
 
89
+ # Execute memory action
90
+ # @param action [String] Action to perform (store, search, entity_info, create_entity, list_entities, context,
91
+ # preferences, learn_preference)
92
+ # @option args [String] :content Fact content to store
93
+ # @option args [String] :category Fact category (relationship, milestone, status, preference, context)
94
+ # @option args [String] :entity_type PARA entity type (projects, areas, resources, archives)
95
+ # @option args [String] :entity_name Entity name
96
+ # @option args [String] :query Search query
97
+ # @option args [String] :entity_subtype Entity subtype for creation (project, person, company, topic)
98
+ # @option args [String] :preference_category Preference category
99
+ # @option args [String] :preference_key Preference key
100
+ # @option args [String] :preference_value Preference value
101
+ # @return [String] Action result or error message
81
102
  def execute(action:, **args)
82
103
  return error("PARA memory not available. Configure memory_dir in agent settings.") unless para_manager
83
104
 
@@ -105,10 +126,15 @@ module Pocketrb
105
126
 
106
127
  private
107
128
 
129
+ # Access the PARA manager from context
130
+ # @return [Object, nil]
108
131
  def para_manager
109
132
  @context[:para_manager]
110
133
  end
111
134
 
135
+ # Store a fact in the knowledge graph
136
+ # @param args [Hash] options including :content, :category, :entity_type, :entity_name
137
+ # @return [String] confirmation or error message
112
138
  def store_fact(args)
113
139
  content = args[:content]
114
140
  return error("Content required") if content.nil? || content.empty?
@@ -131,6 +157,9 @@ module Pocketrb
131
157
  end
132
158
  end
133
159
 
160
+ # Search across knowledge graph, daily notes, and preferences
161
+ # @param query [String] search query
162
+ # @return [String] formatted search results
134
163
  def search_memory(query)
135
164
  return error("Query required") if query.nil? || query.empty?
136
165
 
@@ -166,6 +195,10 @@ module Pocketrb
166
195
  lines.join("\n")
167
196
  end
168
197
 
198
+ # Get summary information for an entity
199
+ # @param entity_type [String] PARA type (projects, areas, resources, archives)
200
+ # @param entity_name [String] entity name
201
+ # @return [String] entity summary or error message
169
202
  def get_entity_info(entity_type, entity_name)
170
203
  return error("Entity type and name required") unless entity_type && entity_name
171
204
 
@@ -175,6 +208,9 @@ module Pocketrb
175
208
  summary
176
209
  end
177
210
 
211
+ # Create a new entity in the knowledge graph
212
+ # @param args [Hash] options including :entity_subtype, :entity_name, :content
213
+ # @return [String] confirmation or error message
178
214
  def create_entity(args)
179
215
  subtype = args[:entity_subtype]
180
216
  name = args[:entity_name]
@@ -204,6 +240,9 @@ module Pocketrb
204
240
  end
205
241
  end
206
242
 
243
+ # List entities, optionally filtered by type
244
+ # @param entity_type [String, nil] PARA type to filter by, or nil for all
245
+ # @return [String] formatted entity list
207
246
  def list_entities(entity_type)
208
247
  if entity_type
209
248
  entities = para_manager.knowledge_graph.list_entities(entity_type.to_sym)
@@ -220,6 +259,9 @@ module Pocketrb
220
259
  end
221
260
  end
222
261
 
262
+ # Get relevant context for a query or full summary
263
+ # @param query [String, nil] context query, or nil for full summary
264
+ # @return [String] relevant context
223
265
  def get_context(query)
224
266
  if query && !query.empty?
225
267
  para_manager.relevant_context(query)
@@ -228,6 +270,8 @@ module Pocketrb
228
270
  end
229
271
  end
230
272
 
273
+ # Get all learned user preferences
274
+ # @return [String] formatted preference list
231
275
  def get_preferences
232
276
  prefs = para_manager.get_preferences
233
277
  return "No learned preferences yet." if prefs.empty?
@@ -243,6 +287,9 @@ module Pocketrb
243
287
  lines.join("\n")
244
288
  end
245
289
 
290
+ # Store a learned user preference
291
+ # @param args [Hash] options including :preference_category, :preference_key, :preference_value
292
+ # @return [String] confirmation or error message
246
293
  def learn_preference(args)
247
294
  category = args[:preference_category]
248
295
  key = args[:preference_key]
@@ -4,14 +4,20 @@ module Pocketrb
4
4
  module Tools
5
5
  # Read file contents
6
6
  class ReadFile < Base
7
+ # Tool name
8
+ # @return [String]
7
9
  def name
8
10
  "read_file"
9
11
  end
10
12
 
13
+ # Tool description
14
+ # @return [String]
11
15
  def description
12
16
  "Read the contents of a file. Returns the file content as text."
13
17
  end
14
18
 
19
+ # Parameter schema
20
+ # @return [Hash]
15
21
  def parameters
16
22
  {
17
23
  type: "object",
@@ -33,6 +39,11 @@ module Pocketrb
33
39
  }
34
40
  end
35
41
 
42
+ # Execute file read operation
43
+ # @param path [String] File path (relative or absolute)
44
+ # @param offset [Integer, nil] Starting line number (1-indexed)
45
+ # @param limit [Integer, nil] Maximum lines to read
46
+ # @return [String] File content or error message
36
47
  def execute(path:, offset: nil, limit: nil)
37
48
  resolved = validate_path!(path)
38
49
 
@@ -6,6 +6,8 @@ module Pocketrb
6
6
  class Registry
7
7
  attr_reader :context
8
8
 
9
+ # Initialize tools registry
10
+ # @param context [Hash] Context to pass to tool instances (defaults to empty hash)
9
11
  def initialize(context = {})
10
12
  @tools = {}
11
13
  @context = context
@@ -35,7 +37,7 @@ module Pocketrb
35
37
 
36
38
  # Get a tool by name
37
39
  # @param name [String] Tool name
38
- # @return [Base|nil]
40
+ # @return [Base, nil]
39
41
  def get(name)
40
42
  @tools[name]
41
43
  end
@@ -62,7 +64,8 @@ module Pocketrb
62
64
  end
63
65
 
64
66
  # Get Anthropic-format definitions
65
- # @return [Array<Hash>]
67
+ # @param filter_unavailable [Boolean] Exclude unavailable tools (defaults to true)
68
+ # @return [Array<Hash>] Tool definitions in Anthropic format
66
69
  def anthropic_definitions(filter_unavailable: true)
67
70
  tools = filter_unavailable ? available_tools : @tools.values
68
71
  tools.map(&:to_anthropic_definition)
@@ -113,6 +116,8 @@ module Pocketrb
113
116
  end
114
117
 
115
118
  # Update context for all tools
119
+ # @param new_context [Hash] New context values to merge
120
+ # @return [void]
116
121
  def update_context(new_context)
117
122
  @context = @context.merge(new_context)
118
123
  @tools.each_value { |tool| tool.instance_variable_set(:@context, @context) }
@@ -140,8 +145,11 @@ module Pocketrb
140
145
 
141
146
  private
142
147
 
143
- # Filter arguments to only include those defined in tool's parameter schema
144
- # This prevents LLM from passing unexpected arguments like 'description'
148
+ # Filter arguments to only include those defined in tool's parameter schema.
149
+ # This prevents LLM from passing unexpected arguments like 'description'.
150
+ # @param tool [Base] tool instance with parameter schema
151
+ # @param args [Hash] raw arguments from LLM
152
+ # @return [Hash] filtered arguments matching the schema
145
153
  def filter_arguments(tool, args)
146
154
  schema = tool.parameters
147
155
  return args unless schema.is_a?(Hash) && schema[:properties]