swarm_sdk 2.7.14 → 3.0.0.alpha2

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +16 -0
  3. data/lib/swarm_sdk/ruby_llm_patches/init.rb +4 -1
  4. data/lib/swarm_sdk/v3/agent.rb +1165 -0
  5. data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
  6. data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
  7. data/lib/swarm_sdk/v3/configuration.rb +490 -0
  8. data/lib/swarm_sdk/v3/debug_log.rb +86 -0
  9. data/lib/swarm_sdk/v3/event_stream.rb +130 -0
  10. data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
  11. data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
  12. data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
  13. data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
  14. data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
  15. data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
  16. data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
  17. data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
  18. data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
  19. data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
  20. data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
  21. data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
  22. data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
  23. data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
  24. data/lib/swarm_sdk/v3/memory/card.rb +206 -0
  25. data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
  26. data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
  27. data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
  28. data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
  29. data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
  30. data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
  31. data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
  32. data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
  33. data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
  34. data/lib/swarm_sdk/v3/memory/store.rb +489 -0
  35. data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
  36. data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
  37. data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
  38. data/lib/swarm_sdk/v3/tools/base.rb +80 -0
  39. data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
  40. data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
  41. data/lib/swarm_sdk/v3/tools/document_converters/base.rb +84 -0
  42. data/lib/swarm_sdk/v3/tools/document_converters/docx_converter.rb +120 -0
  43. data/lib/swarm_sdk/v3/tools/document_converters/pdf_converter.rb +111 -0
  44. data/lib/swarm_sdk/v3/tools/document_converters/xlsx_converter.rb +128 -0
  45. data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
  46. data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
  47. data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
  48. data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
  49. data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
  50. data/lib/swarm_sdk/v3/tools/read.rb +213 -0
  51. data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
  52. data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
  53. data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
  54. data/lib/swarm_sdk/v3/tools/think.rb +88 -0
  55. data/lib/swarm_sdk/v3/tools/write.rb +87 -0
  56. data/lib/swarm_sdk/v3.rb +145 -0
  57. metadata +88 -149
  58. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
  59. data/lib/swarm_sdk/agent/builder.rb +0 -705
  60. data/lib/swarm_sdk/agent/chat.rb +0 -1438
  61. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
  62. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  63. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  64. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -85
  65. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
  66. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  67. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  68. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -134
  69. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  70. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
  71. data/lib/swarm_sdk/agent/context.rb +0 -115
  72. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  73. data/lib/swarm_sdk/agent/definition.rb +0 -588
  74. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
  75. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -173
  76. data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
  77. data/lib/swarm_sdk/agent_registry.rb +0 -146
  78. data/lib/swarm_sdk/builders/base_builder.rb +0 -558
  79. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  80. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -42
  81. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  82. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  83. data/lib/swarm_sdk/config.rb +0 -368
  84. data/lib/swarm_sdk/configuration/parser.rb +0 -397
  85. data/lib/swarm_sdk/configuration/translator.rb +0 -285
  86. data/lib/swarm_sdk/configuration.rb +0 -165
  87. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  88. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
  89. data/lib/swarm_sdk/context_compactor.rb +0 -335
  90. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  91. data/lib/swarm_sdk/context_management/context.rb +0 -328
  92. data/lib/swarm_sdk/custom_tool_registry.rb +0 -226
  93. data/lib/swarm_sdk/defaults.rb +0 -251
  94. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  95. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  96. data/lib/swarm_sdk/hooks/context.rb +0 -197
  97. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  98. data/lib/swarm_sdk/hooks/error.rb +0 -29
  99. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  100. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  101. data/lib/swarm_sdk/hooks/result.rb +0 -150
  102. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -256
  103. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  104. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  105. data/lib/swarm_sdk/log_collector.rb +0 -227
  106. data/lib/swarm_sdk/log_stream.rb +0 -127
  107. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  108. data/lib/swarm_sdk/model_aliases.json +0 -8
  109. data/lib/swarm_sdk/models.json +0 -44002
  110. data/lib/swarm_sdk/models.rb +0 -161
  111. data/lib/swarm_sdk/node_context.rb +0 -245
  112. data/lib/swarm_sdk/observer/builder.rb +0 -81
  113. data/lib/swarm_sdk/observer/config.rb +0 -45
  114. data/lib/swarm_sdk/observer/manager.rb +0 -248
  115. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  116. data/lib/swarm_sdk/permissions/config.rb +0 -239
  117. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  118. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  119. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  120. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  121. data/lib/swarm_sdk/plugin.rb +0 -309
  122. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  123. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  124. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -119
  125. data/lib/swarm_sdk/restore_result.rb +0 -65
  126. data/lib/swarm_sdk/result.rb +0 -241
  127. data/lib/swarm_sdk/snapshot.rb +0 -156
  128. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  129. data/lib/swarm_sdk/state_restorer.rb +0 -476
  130. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  131. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -648
  132. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -204
  133. data/lib/swarm_sdk/swarm/builder.rb +0 -256
  134. data/lib/swarm_sdk/swarm/executor.rb +0 -446
  135. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -162
  136. data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -361
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -290
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
  141. data/lib/swarm_sdk/swarm.rb +0 -973
  142. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  143. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  144. data/lib/swarm_sdk/tools/base.rb +0 -63
  145. data/lib/swarm_sdk/tools/bash.rb +0 -280
  146. data/lib/swarm_sdk/tools/clock.rb +0 -46
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -389
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -167
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
  160. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  161. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  162. data/lib/swarm_sdk/tools/read.rb +0 -261
  163. data/lib/swarm_sdk/tools/registry.rb +0 -205
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  166. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  167. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  168. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -273
  169. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  170. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  171. data/lib/swarm_sdk/tools/think.rb +0 -100
  172. data/lib/swarm_sdk/tools/todo_write.rb +0 -237
  173. data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
  174. data/lib/swarm_sdk/tools/write.rb +0 -112
  175. data/lib/swarm_sdk/transcript_builder.rb +0 -278
  176. data/lib/swarm_sdk/utils.rb +0 -68
  177. data/lib/swarm_sdk/validation_result.rb +0 -33
  178. data/lib/swarm_sdk/version.rb +0 -5
  179. data/lib/swarm_sdk/workflow/agent_config.rb +0 -95
  180. data/lib/swarm_sdk/workflow/builder.rb +0 -227
  181. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  182. data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
  183. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
  184. data/lib/swarm_sdk/workflow.rb +0 -589
  185. data/lib/swarm_sdk.rb +0 -721
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Configuration facade that delegates to Parser and Translator
5
- #
6
- # This class maintains the public API while internally delegating to:
7
- # - Configuration::Parser - YAML parsing, validation, and normalization
8
- # - Configuration::Translator - Translation to Swarm/Workflow DSL builders
9
- #
10
- # ## Public API (unchanged)
11
- # - Configuration.load_file(path) - Load from file
12
- # - Configuration.new(yaml_content, base_dir:) - Load from string
13
- # - config.load_and_validate - Parse and validate
14
- # - config.to_swarm(allow_filesystem_tools:) - Convert to Swarm/Workflow
15
- # - config.agent_names - Get list of agent names
16
- # - config.connections_for(agent_name) - Get delegation targets
17
- #
18
- # ## Architecture
19
- # The facade pattern keeps backward compatibility while separating concerns:
20
- # - Parser handles all YAML parsing and validation logic
21
- # - Translator handles all DSL builder translation logic
22
- # - Configuration delegates to both, exposing parsed data via attr_readers
23
- class Configuration
24
- attr_reader :config_type,
25
- :swarm_name,
26
- :swarm_id,
27
- :lead_agent,
28
- :start_node,
29
- :agents,
30
- :all_agents_config,
31
- :swarm_hooks,
32
- :all_agents_hooks,
33
- :scratchpad_enabled,
34
- :nodes,
35
- :external_swarms
36
-
37
- class << self
38
- # Load configuration from YAML file
39
- #
40
- # @param path [String, Pathname] Path to YAML configuration file
41
- # @param env_interpolation [Boolean, nil] Whether to interpolate environment variables.
42
- # When nil, uses the global SwarmSDK.config.env_interpolation setting.
43
- # When true, interpolates ${VAR} and ${VAR:=default} patterns.
44
- # When false, skips interpolation entirely.
45
- # @return [Configuration] Validated configuration instance
46
- # @raise [ConfigurationError] If file not found or invalid
47
- def load_file(path, env_interpolation: nil)
48
- path = Pathname.new(path).expand_path
49
-
50
- unless path.exist?
51
- raise ConfigurationError, "Configuration file not found: #{path}"
52
- end
53
-
54
- yaml_content = File.read(path)
55
- base_dir = path.dirname
56
-
57
- new(yaml_content, base_dir: base_dir, env_interpolation: env_interpolation).tap(&:load_and_validate)
58
- rescue Errno::ENOENT
59
- raise ConfigurationError, "Configuration file not found: #{path}"
60
- end
61
- end
62
-
63
- # Initialize configuration from YAML string
64
- #
65
- # @param yaml_content [String] YAML configuration content
66
- # @param base_dir [String, Pathname] Base directory for resolving agent file paths (default: Dir.pwd)
67
- # @param env_interpolation [Boolean, nil] Whether to interpolate environment variables.
68
- # When nil, uses the global SwarmSDK.config.env_interpolation setting.
69
- # When true, interpolates ${VAR} and ${VAR:=default} patterns.
70
- # When false, skips interpolation entirely.
71
- def initialize(yaml_content, base_dir: Dir.pwd, env_interpolation: nil)
72
- raise ArgumentError, "yaml_content cannot be nil" if yaml_content.nil?
73
- raise ArgumentError, "base_dir cannot be nil" if base_dir.nil?
74
-
75
- @yaml_content = yaml_content
76
- @base_dir = Pathname.new(base_dir).expand_path
77
- @env_interpolation = env_interpolation
78
- @parser = nil
79
- @translator = nil
80
- end
81
-
82
- # Parse and validate YAML configuration
83
- #
84
- # Delegates to Parser for all parsing logic, then syncs parsed data
85
- # to instance variables for backward compatibility.
86
- #
87
- # @return [self]
88
- def load_and_validate
89
- @parser = Parser.new(@yaml_content, base_dir: @base_dir, env_interpolation: @env_interpolation)
90
- @parser.parse
91
-
92
- # Sync parsed data to instance variables for backward compatibility
93
- sync_from_parser
94
-
95
- self
96
- end
97
-
98
- def agent_names
99
- @agents.keys
100
- end
101
-
102
- def connections_for(agent_name)
103
- agent_config = @agents[agent_name]
104
- return [] unless agent_config
105
-
106
- delegates = agent_config[:delegates_to] || []
107
-
108
- # Handle both array and hash formats for delegates_to
109
- case delegates
110
- when Array
111
- # Array of symbols: [:frontend, :backend]
112
- # OR array of hashes: [{agent: :frontend, tool_name: "Custom"}]
113
- delegates.map do |item|
114
- case item
115
- when Symbol, String
116
- item.to_sym
117
- when Hash
118
- # Extract agent name from hash format
119
- agent_name = item[:agent] || item["agent"]
120
- agent_name&.to_sym
121
- end
122
- end.compact # Remove nils from malformed hashes
123
- when Hash
124
- # Hash format: {frontend: "Custom", backend: nil}
125
- delegates.keys.map(&:to_sym)
126
- else
127
- []
128
- end
129
- end
130
-
131
- # Convert configuration to Swarm or Workflow using appropriate builder
132
- #
133
- # Delegates to Translator for all DSL translation logic.
134
- #
135
- # @param allow_filesystem_tools [Boolean, nil] Whether to allow filesystem tools (nil uses global setting)
136
- # @return [Swarm, Workflow] Configured swarm or workflow
137
- def to_swarm(allow_filesystem_tools: nil)
138
- raise ConfigurationError, "Configuration not loaded. Call load_and_validate first." unless @parser
139
-
140
- @translator = Translator.new(@parser)
141
- @translator.to_swarm(allow_filesystem_tools: allow_filesystem_tools)
142
- end
143
-
144
- private
145
-
146
- # Sync parsed data from Parser to instance variables
147
- #
148
- # This maintains backward compatibility with code that accesses
149
- # @config_type, @agents, etc. directly via attr_readers.
150
- def sync_from_parser
151
- @config_type = @parser.config_type
152
- @swarm_name = @parser.swarm_name
153
- @swarm_id = @parser.swarm_id
154
- @lead_agent = @parser.lead_agent
155
- @start_node = @parser.start_node
156
- @agents = @parser.agents
157
- @all_agents_config = @parser.all_agents_config
158
- @swarm_hooks = @parser.swarm_hooks
159
- @all_agents_hooks = @parser.all_agents_hooks
160
- @external_swarms = @parser.external_swarms
161
- @nodes = @parser.nodes
162
- @scratchpad_enabled = @parser.scratchpad_mode # NOTE: attr_reader says scratchpad_enabled
163
- end
164
- end
165
- end
@@ -1,147 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class ContextCompactor
5
- # Metrics tracks compression statistics
6
- #
7
- # Provides detailed information about the compression operation:
8
- # - Message counts (before/after)
9
- # - Token counts (before/after)
10
- # - Compression ratio
11
- # - Time taken
12
- # - Summary of changes
13
- #
14
- # ## Usage
15
- #
16
- # metrics = agent.compact_context
17
- # puts metrics.summary
18
- # puts "Compressed from #{metrics.original_tokens} to #{metrics.compressed_tokens} tokens"
19
- # puts "Compression ratio: #{(metrics.compression_ratio * 100).round(1)}%"
20
- #
21
- class Metrics
22
- attr_reader :original_messages, :compressed_messages, :time_taken
23
-
24
- # Initialize metrics from compression operation
25
- #
26
- # @param original_messages [Array<RubyLLM::Message>] Messages before compression
27
- # @param compressed_messages [Array<RubyLLM::Message>] Messages after compression
28
- # @param time_taken [Float] Time taken in seconds
29
- def initialize(original_messages:, compressed_messages:, time_taken:)
30
- @original_messages = original_messages
31
- @compressed_messages = compressed_messages
32
- @time_taken = time_taken
33
- end
34
-
35
- # Number of messages before compression
36
- #
37
- # @return [Integer] Original message count
38
- def original_message_count
39
- @original_messages.size
40
- end
41
-
42
- # Number of messages after compression
43
- #
44
- # @return [Integer] Compressed message count
45
- def compressed_message_count
46
- @compressed_messages.size
47
- end
48
-
49
- # Number of messages removed
50
- #
51
- # @return [Integer] Messages removed
52
- def messages_removed
53
- original_message_count - compressed_message_count
54
- end
55
-
56
- # Number of checkpoint summary messages created
57
- #
58
- # @return [Integer] Checkpoint messages
59
- def messages_summarized
60
- @compressed_messages.count do |msg|
61
- msg.role == :system && msg.content.to_s.include?("CONVERSATION CHECKPOINT")
62
- end
63
- end
64
-
65
- # Estimated tokens before compression
66
- #
67
- # @return [Integer] Original token count
68
- def original_tokens
69
- @original_tokens ||= TokenCounter.estimate_messages(@original_messages)
70
- end
71
-
72
- # Estimated tokens after compression
73
- #
74
- # @return [Integer] Compressed token count
75
- def compressed_tokens
76
- @compressed_tokens ||= TokenCounter.estimate_messages(@compressed_messages)
77
- end
78
-
79
- # Number of tokens removed
80
- #
81
- # @return [Integer] Tokens removed
82
- def tokens_removed
83
- original_tokens - compressed_tokens
84
- end
85
-
86
- # Compression ratio (compressed / original)
87
- #
88
- # @return [Float] Ratio between 0.0 and 1.0
89
- def compression_ratio
90
- return 0.0 if original_tokens.zero?
91
-
92
- compressed_tokens.to_f / original_tokens
93
- end
94
-
95
- # Compression factor (original / compressed)
96
- #
97
- # e.g., 5.0 means compressed to 1/5th of original size
98
- #
99
- # @return [Float] Compression factor
100
- def compression_factor
101
- return 0.0 if compressed_tokens.zero?
102
-
103
- original_tokens.to_f / compressed_tokens
104
- end
105
-
106
- # Compression percentage
107
- #
108
- # @return [Float] Percentage of original size (0-100)
109
- def compression_percentage
110
- (compression_ratio * 100).round(2)
111
- end
112
-
113
- # Generate a human-readable summary
114
- #
115
- # @return [String] Summary text
116
- def summary
117
- <<~SUMMARY
118
- Context Compression Results:
119
- - Messages: #{original_message_count} → #{compressed_message_count} (-#{messages_removed})
120
- - Estimated tokens: #{original_tokens} → #{compressed_tokens} (-#{tokens_removed})
121
- - Compression ratio: #{compression_factor.round(1)}:1 (#{compression_percentage}%)
122
- - Checkpoints created: #{messages_summarized}
123
- - Time taken: #{time_taken.round(3)}s
124
- SUMMARY
125
- end
126
-
127
- # Convert metrics to hash for logging
128
- #
129
- # @return [Hash] Metrics as hash
130
- def to_h
131
- {
132
- original_message_count: original_message_count,
133
- compressed_message_count: compressed_message_count,
134
- messages_removed: messages_removed,
135
- messages_summarized: messages_summarized,
136
- original_tokens: original_tokens,
137
- compressed_tokens: compressed_tokens,
138
- tokens_removed: tokens_removed,
139
- compression_ratio: compression_ratio.round(4),
140
- compression_factor: compression_factor.round(2),
141
- compression_percentage: compression_percentage,
142
- time_taken: time_taken.round(3),
143
- }
144
- end
145
- end
146
- end
147
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- class ContextCompactor
5
- # TokenCounter provides token estimation for messages
6
- #
7
- # This uses a simple heuristic approach:
8
- # - ~4 characters per token for English prose
9
- # - ~3.5 characters per token for code
10
- #
11
- # For production use with OpenAI models, consider using the tiktoken gem
12
- # for accurate token counting. For Claude models, use Claude's token API.
13
- #
14
- # ## Usage
15
- #
16
- # tokens = TokenCounter.estimate_message(message)
17
- # total_tokens = TokenCounter.estimate_messages(messages)
18
- #
19
- class TokenCounter
20
- class << self
21
- # Estimate tokens for a single message
22
- #
23
- # @param message [RubyLLM::Message] Message to estimate
24
- # @return [Integer] Estimated token count
25
- def estimate_message(message)
26
- case message.role
27
- when :user, :assistant
28
- estimate_content(message.content)
29
- when :system
30
- estimate_content(message.content)
31
- when :tool
32
- # Tool results typically have overhead
33
- base_overhead = 50
34
- content_tokens = estimate_content(message.content)
35
- base_overhead + content_tokens
36
- else
37
- # Unknown message type
38
- begin
39
- estimate_content(message.content)
40
- rescue
41
- 0
42
- end
43
- end
44
- end
45
-
46
- # Estimate tokens for multiple messages
47
- #
48
- # @param messages [Array<RubyLLM::Message>] Messages to estimate
49
- # @return [Integer] Total estimated token count
50
- def estimate_messages(messages)
51
- messages.sum { |msg| estimate_message(msg) }
52
- end
53
-
54
- # Estimate tokens for content string
55
- #
56
- # Uses heuristic to detect code vs prose and adjust accordingly.
57
- #
58
- # @param content [String, RubyLLM::Content, nil] Content to estimate
59
- # @return [Integer] Estimated token count
60
- def estimate_content(content)
61
- return 0 if content.nil?
62
-
63
- # Handle RubyLLM::Content objects
64
- text = if content.respond_to?(:to_s)
65
- content.to_s
66
- else
67
- content
68
- end
69
-
70
- return 0 if text.empty?
71
-
72
- # Detect if content is mostly code
73
- code_ratio = detect_code_ratio(text)
74
-
75
- # Choose characters per token based on content type
76
- chars_per_token = if code_ratio > 0.1
77
- SwarmSDK.config.chars_per_token_code # Code
78
- else
79
- SwarmSDK.config.chars_per_token_prose # Prose
80
- end
81
-
82
- (text.length / chars_per_token).ceil
83
- end
84
-
85
- private
86
-
87
- # Detect ratio of code characters to total characters
88
- #
89
- # @param text [String] Text to analyze
90
- # @return [Float] Ratio of code indicators (0.0 to 1.0)
91
- def detect_code_ratio(text)
92
- # Count code indicator characters
93
- code_chars = text.scan(/[{}()\[\];]/).length
94
-
95
- return 0.0 if text.empty?
96
-
97
- code_chars.to_f / text.length
98
- end
99
- end
100
- end
101
- end
102
- end