swarm_sdk 2.7.14 → 3.0.0.alpha1

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 (181) 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/edit.rb +111 -0
  42. data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
  43. data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
  44. data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
  45. data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
  46. data/lib/swarm_sdk/v3/tools/read.rb +181 -0
  47. data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
  48. data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
  49. data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
  50. data/lib/swarm_sdk/v3/tools/think.rb +88 -0
  51. data/lib/swarm_sdk/v3/tools/write.rb +87 -0
  52. data/lib/swarm_sdk/v3.rb +145 -0
  53. metadata +83 -148
  54. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
  55. data/lib/swarm_sdk/agent/builder.rb +0 -705
  56. data/lib/swarm_sdk/agent/chat.rb +0 -1438
  57. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
  58. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  59. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  60. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -85
  61. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
  62. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  63. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  64. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -134
  65. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  66. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
  67. data/lib/swarm_sdk/agent/context.rb +0 -115
  68. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  69. data/lib/swarm_sdk/agent/definition.rb +0 -588
  70. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
  71. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -173
  72. data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
  73. data/lib/swarm_sdk/agent_registry.rb +0 -146
  74. data/lib/swarm_sdk/builders/base_builder.rb +0 -558
  75. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  76. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -42
  77. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  78. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  79. data/lib/swarm_sdk/config.rb +0 -368
  80. data/lib/swarm_sdk/configuration/parser.rb +0 -397
  81. data/lib/swarm_sdk/configuration/translator.rb +0 -285
  82. data/lib/swarm_sdk/configuration.rb +0 -165
  83. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  84. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
  85. data/lib/swarm_sdk/context_compactor.rb +0 -335
  86. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  87. data/lib/swarm_sdk/context_management/context.rb +0 -328
  88. data/lib/swarm_sdk/custom_tool_registry.rb +0 -226
  89. data/lib/swarm_sdk/defaults.rb +0 -251
  90. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  91. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  92. data/lib/swarm_sdk/hooks/context.rb +0 -197
  93. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  94. data/lib/swarm_sdk/hooks/error.rb +0 -29
  95. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  96. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  97. data/lib/swarm_sdk/hooks/result.rb +0 -150
  98. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -256
  99. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  100. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  101. data/lib/swarm_sdk/log_collector.rb +0 -227
  102. data/lib/swarm_sdk/log_stream.rb +0 -127
  103. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  104. data/lib/swarm_sdk/model_aliases.json +0 -8
  105. data/lib/swarm_sdk/models.json +0 -44002
  106. data/lib/swarm_sdk/models.rb +0 -161
  107. data/lib/swarm_sdk/node_context.rb +0 -245
  108. data/lib/swarm_sdk/observer/builder.rb +0 -81
  109. data/lib/swarm_sdk/observer/config.rb +0 -45
  110. data/lib/swarm_sdk/observer/manager.rb +0 -248
  111. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  112. data/lib/swarm_sdk/permissions/config.rb +0 -239
  113. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  114. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  115. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  116. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  117. data/lib/swarm_sdk/plugin.rb +0 -309
  118. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  119. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  120. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -119
  121. data/lib/swarm_sdk/restore_result.rb +0 -65
  122. data/lib/swarm_sdk/result.rb +0 -241
  123. data/lib/swarm_sdk/snapshot.rb +0 -156
  124. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  125. data/lib/swarm_sdk/state_restorer.rb +0 -476
  126. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  127. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -648
  128. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -204
  129. data/lib/swarm_sdk/swarm/builder.rb +0 -256
  130. data/lib/swarm_sdk/swarm/executor.rb +0 -446
  131. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -162
  132. data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
  133. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -361
  134. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -290
  135. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  136. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
  137. data/lib/swarm_sdk/swarm.rb +0 -973
  138. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  139. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  140. data/lib/swarm_sdk/tools/base.rb +0 -63
  141. data/lib/swarm_sdk/tools/bash.rb +0 -280
  142. data/lib/swarm_sdk/tools/clock.rb +0 -46
  143. data/lib/swarm_sdk/tools/delegate.rb +0 -389
  144. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  145. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  146. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  147. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  148. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  149. data/lib/swarm_sdk/tools/edit.rb +0 -145
  150. data/lib/swarm_sdk/tools/glob.rb +0 -166
  151. data/lib/swarm_sdk/tools/grep.rb +0 -235
  152. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  153. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -167
  154. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  155. data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
  156. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  157. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  158. data/lib/swarm_sdk/tools/read.rb +0 -261
  159. data/lib/swarm_sdk/tools/registry.rb +0 -205
  160. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  161. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  163. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  164. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -273
  165. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  166. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  167. data/lib/swarm_sdk/tools/think.rb +0 -100
  168. data/lib/swarm_sdk/tools/todo_write.rb +0 -237
  169. data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
  170. data/lib/swarm_sdk/tools/write.rb +0 -112
  171. data/lib/swarm_sdk/transcript_builder.rb +0 -278
  172. data/lib/swarm_sdk/utils.rb +0 -68
  173. data/lib/swarm_sdk/validation_result.rb +0 -33
  174. data/lib/swarm_sdk/version.rb +0 -5
  175. data/lib/swarm_sdk/workflow/agent_config.rb +0 -95
  176. data/lib/swarm_sdk/workflow/builder.rb +0 -227
  177. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  178. data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
  179. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
  180. data/lib/swarm_sdk/workflow.rb +0 -589
  181. data/lib/swarm_sdk.rb +0 -721
@@ -1,368 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Centralized configuration for SwarmSDK
5
- #
6
- # Config provides a single entry point for all SwarmSDK configuration,
7
- # including API keys (proxied to RubyLLM), defaults override, and
8
- # WebFetch settings.
9
- #
10
- # ## Priority Order
11
- #
12
- # Configuration values are resolved in this order:
13
- # 1. Explicit value (set via SwarmSDK.configure)
14
- # 2. Environment variable
15
- # 3. Module default (from SwarmSDK::Defaults)
16
- #
17
- # ## API Key Proxying
18
- #
19
- # API keys are automatically proxied to RubyLLM.config when set,
20
- # ensuring RubyLLM always has the correct credentials.
21
- #
22
- # @example Basic configuration
23
- # SwarmSDK.configure do |config|
24
- # config.openai_api_key = "sk-..."
25
- # config.default_model = "claude-sonnet-4"
26
- # config.agent_request_timeout = 600
27
- # end
28
- #
29
- # @example Testing setup
30
- # def setup
31
- # SwarmSDK.reset_config!
32
- # end
33
- class Config
34
- # API keys that proxy to RubyLLM.config
35
- # Maps SwarmSDK config key => [RubyLLM config key, ENV variable]
36
- API_KEY_MAPPINGS = {
37
- openai_api_key: [:openai_api_key, "OPENAI_API_KEY"],
38
- openai_api_base: [:openai_api_base, "OPENAI_API_BASE"],
39
- openai_organization_id: [:openai_organization_id, "OPENAI_ORG_ID"],
40
- openai_project_id: [:openai_project_id, "OPENAI_PROJECT_ID"],
41
- anthropic_api_key: [:anthropic_api_key, "ANTHROPIC_API_KEY"],
42
- gemini_api_key: [:gemini_api_key, "GEMINI_API_KEY"],
43
- gemini_api_base: [:gemini_api_base, "GEMINI_API_BASE"],
44
- vertexai_project_id: [:vertexai_project_id, "GOOGLE_CLOUD_PROJECT"],
45
- vertexai_location: [:vertexai_location, "GOOGLE_CLOUD_LOCATION"],
46
- deepseek_api_key: [:deepseek_api_key, "DEEPSEEK_API_KEY"],
47
- mistral_api_key: [:mistral_api_key, "MISTRAL_API_KEY"],
48
- perplexity_api_key: [:perplexity_api_key, "PERPLEXITY_API_KEY"],
49
- openrouter_api_key: [:openrouter_api_key, "OPENROUTER_API_KEY"],
50
- bedrock_api_key: [:bedrock_api_key, "AWS_ACCESS_KEY_ID"],
51
- bedrock_secret_key: [:bedrock_secret_key, "AWS_SECRET_ACCESS_KEY"],
52
- bedrock_region: [:bedrock_region, "AWS_REGION"],
53
- bedrock_session_token: [:bedrock_session_token, "AWS_SESSION_TOKEN"],
54
- ollama_api_base: [:ollama_api_base, "OLLAMA_API_BASE"],
55
- gpustack_api_base: [:gpustack_api_base, "GPUSTACK_API_BASE"],
56
- gpustack_api_key: [:gpustack_api_key, "GPUSTACK_API_KEY"],
57
- }.freeze
58
-
59
- # RubyLLM connection settings that proxy to RubyLLM.config
60
- # Maps SwarmSDK config key => [RubyLLM config key, ENV variable, default value]
61
- RUBYLLM_CONNECTION_MAPPINGS = {
62
- llm_request_timeout: [:request_timeout, "SWARM_SDK_LLM_REQUEST_TIMEOUT", 300],
63
- llm_read_timeout: [:read_timeout, "SWARM_SDK_LLM_READ_TIMEOUT", nil], # nil = use request_timeout
64
- llm_open_timeout: [:open_timeout, "SWARM_SDK_LLM_OPEN_TIMEOUT", 30],
65
- llm_write_timeout: [:write_timeout, "SWARM_SDK_LLM_WRITE_TIMEOUT", 30],
66
- }.freeze
67
-
68
- # SwarmSDK defaults that can be overridden
69
- # Maps config key => [ENV variable, default proc]
70
- DEFAULTS_MAPPINGS = {
71
- default_model: ["SWARM_SDK_DEFAULT_MODEL", -> { Defaults::Agent::MODEL }],
72
- default_provider: ["SWARM_SDK_DEFAULT_PROVIDER", -> { Defaults::Agent::PROVIDER }],
73
- agent_request_timeout: ["SWARM_SDK_AGENT_REQUEST_TIMEOUT", -> { Defaults::Timeouts::AGENT_REQUEST_SECONDS }],
74
- bash_command_timeout: ["SWARM_SDK_BASH_COMMAND_TIMEOUT", -> { Defaults::Timeouts::BASH_COMMAND_MS }],
75
- bash_command_max_timeout: ["SWARM_SDK_BASH_COMMAND_MAX_TIMEOUT", -> { Defaults::Timeouts::BASH_COMMAND_MAX_MS }],
76
- web_fetch_timeout: ["SWARM_SDK_WEB_FETCH_TIMEOUT", -> { Defaults::Timeouts::WEB_FETCH_SECONDS }],
77
- hook_shell_timeout: ["SWARM_SDK_HOOK_SHELL_TIMEOUT", -> { Defaults::Timeouts::HOOK_SHELL_SECONDS }],
78
- transformer_command_timeout: ["SWARM_SDK_TRANSFORMER_COMMAND_TIMEOUT", -> { Defaults::Timeouts::TRANSFORMER_COMMAND_SECONDS }],
79
- global_concurrency_limit: ["SWARM_SDK_GLOBAL_CONCURRENCY_LIMIT", -> { Defaults::Concurrency::GLOBAL_LIMIT }],
80
- local_concurrency_limit: ["SWARM_SDK_LOCAL_CONCURRENCY_LIMIT", -> { Defaults::Concurrency::LOCAL_LIMIT }],
81
- output_character_limit: ["SWARM_SDK_OUTPUT_CHARACTER_LIMIT", -> { Defaults::Limits::OUTPUT_CHARACTERS }],
82
- read_line_limit: ["SWARM_SDK_READ_LINE_LIMIT", -> { Defaults::Limits::READ_LINES }],
83
- line_character_limit: ["SWARM_SDK_LINE_CHARACTER_LIMIT", -> { Defaults::Limits::LINE_CHARACTERS }],
84
- web_fetch_character_limit: ["SWARM_SDK_WEB_FETCH_CHARACTER_LIMIT", -> { Defaults::Limits::WEB_FETCH_CHARACTERS }],
85
- glob_result_limit: ["SWARM_SDK_GLOB_RESULT_LIMIT", -> { Defaults::Limits::GLOB_RESULTS }],
86
- scratchpad_entry_size_limit: ["SWARM_SDK_SCRATCHPAD_ENTRY_SIZE_LIMIT", -> { Defaults::Storage::ENTRY_SIZE_BYTES }],
87
- scratchpad_total_size_limit: ["SWARM_SDK_SCRATCHPAD_TOTAL_SIZE_LIMIT", -> { Defaults::Storage::TOTAL_SIZE_BYTES }],
88
- context_compression_threshold: ["SWARM_SDK_CONTEXT_COMPRESSION_THRESHOLD", -> { Defaults::Context::COMPRESSION_THRESHOLD_PERCENT }],
89
- todowrite_reminder_interval: ["SWARM_SDK_TODOWRITE_REMINDER_INTERVAL", -> { Defaults::Context::TODOWRITE_REMINDER_INTERVAL }],
90
- chars_per_token_prose: ["SWARM_SDK_CHARS_PER_TOKEN_PROSE", -> { Defaults::TokenEstimation::CHARS_PER_TOKEN_PROSE }],
91
- chars_per_token_code: ["SWARM_SDK_CHARS_PER_TOKEN_CODE", -> { Defaults::TokenEstimation::CHARS_PER_TOKEN_CODE }],
92
- mcp_log_level: ["SWARM_SDK_MCP_LOG_LEVEL", -> { Defaults::Logging::MCP_LOG_LEVEL }],
93
- default_execution_timeout: ["SWARM_SDK_DEFAULT_EXECUTION_TIMEOUT", -> { Defaults::Timeouts::EXECUTION_TIMEOUT_SECONDS }],
94
- default_turn_timeout: ["SWARM_SDK_DEFAULT_TURN_TIMEOUT", -> { Defaults::Timeouts::TURN_TIMEOUT_SECONDS }],
95
- mcp_request_timeout: ["SWARM_SDK_MCP_REQUEST_TIMEOUT", -> { Defaults::Timeouts::MCP_REQUEST_SECONDS }],
96
- }.freeze
97
-
98
- # WebFetch and control settings
99
- # Maps config key => [ENV variable, default value]
100
- SETTINGS_MAPPINGS = {
101
- webfetch_provider: ["SWARM_SDK_WEBFETCH_PROVIDER", nil],
102
- webfetch_model: ["SWARM_SDK_WEBFETCH_MODEL", nil],
103
- webfetch_base_url: ["SWARM_SDK_WEBFETCH_BASE_URL", nil],
104
- webfetch_max_tokens: ["SWARM_SDK_WEBFETCH_MAX_TOKENS", 4096],
105
- allow_filesystem_tools: ["SWARM_SDK_ALLOW_FILESYSTEM_TOOLS", true],
106
- env_interpolation: ["SWARM_SDK_ENV_INTERPOLATION", true],
107
- streaming: ["SWARM_SDK_STREAMING", true],
108
- mcp_ssl_verify: ["SWARM_SDK_MCP_SSL_VERIFY", true],
109
- }.freeze
110
-
111
- class << self
112
- # Get the singleton Config instance
113
- #
114
- # @return [Config] The singleton instance
115
- def instance
116
- @instance ||= new
117
- end
118
-
119
- # Reset the Config instance
120
- #
121
- # Clears all configuration including explicit values and cached ENV values.
122
- # Use in tests to ensure clean state.
123
- #
124
- # @return [void]
125
- def reset!
126
- @instance = nil
127
- end
128
- end
129
-
130
- # Initialize a new Config instance
131
- #
132
- # @note Use Config.instance instead of new for the singleton pattern
133
- def initialize
134
- @explicit_values = {}
135
- @env_values = {}
136
- @env_loaded = false
137
- @env_mutex = Mutex.new
138
- end
139
-
140
- # ========== API Key Accessors (with RubyLLM proxying) ==========
141
-
142
- # @!method openai_api_key
143
- # Get the OpenAI API key
144
- # @return [String, nil] The API key
145
- #
146
- # @!method openai_api_key=(value)
147
- # Set the OpenAI API key (proxied to RubyLLM)
148
- # @param value [String] The API key
149
-
150
- API_KEY_MAPPINGS.each_key do |config_key|
151
- ruby_llm_key, _ = API_KEY_MAPPINGS[config_key]
152
-
153
- # Getter
154
- define_method(config_key) do
155
- ensure_env_loaded!
156
- @explicit_values[config_key] || @env_values[config_key]
157
- end
158
-
159
- # Setter with RubyLLM proxying
160
- define_method("#{config_key}=") do |value|
161
- @explicit_values[config_key] = value
162
- RubyLLM.config.public_send("#{ruby_llm_key}=", value) if value
163
- end
164
- end
165
-
166
- # ========== RubyLLM Connection Accessors (with RubyLLM proxying) ==========
167
-
168
- # @!method llm_request_timeout
169
- # Get the LLM request timeout (seconds)
170
- # @return [Integer] The timeout (default: 300)
171
- #
172
- # @!method llm_read_timeout
173
- # Get the LLM read timeout (seconds) - time to wait between chunks
174
- # @return [Integer, nil] The timeout (nil = use request_timeout)
175
- #
176
- # @!method llm_open_timeout
177
- # Get the LLM connection open timeout (seconds)
178
- # @return [Integer] The timeout (default: 30)
179
- #
180
- # @!method llm_write_timeout
181
- # Get the LLM write timeout (seconds)
182
- # @return [Integer] The timeout (default: 30)
183
-
184
- RUBYLLM_CONNECTION_MAPPINGS.each_key do |config_key|
185
- ruby_llm_key, _env_key, default_value = RUBYLLM_CONNECTION_MAPPINGS[config_key]
186
-
187
- # Getter with default fallback
188
- define_method(config_key) do
189
- ensure_env_loaded!
190
- if @explicit_values.key?(config_key)
191
- @explicit_values[config_key]
192
- elsif @env_values.key?(config_key)
193
- @env_values[config_key]
194
- else
195
- default_value
196
- end
197
- end
198
-
199
- # Setter with RubyLLM proxying
200
- define_method("#{config_key}=") do |value|
201
- @explicit_values[config_key] = value
202
- RubyLLM.config.public_send("#{ruby_llm_key}=", value)
203
- end
204
- end
205
-
206
- # ========== Defaults Accessors (with module constant fallback) ==========
207
-
208
- # @!method default_model
209
- # Get the default model
210
- # @return [String] The default model (falls back to Defaults::Agent::MODEL)
211
- #
212
- # @!method default_model=(value)
213
- # Set the default model
214
- # @param value [String] The default model
215
-
216
- DEFAULTS_MAPPINGS.each_key do |config_key|
217
- _env_key, default_proc = DEFAULTS_MAPPINGS[config_key]
218
-
219
- # Getter with default fallback
220
- define_method(config_key) do
221
- ensure_env_loaded!
222
- @explicit_values[config_key] || @env_values[config_key] || default_proc.call
223
- end
224
-
225
- # Setter
226
- define_method("#{config_key}=") do |value|
227
- @explicit_values[config_key] = value
228
- end
229
- end
230
-
231
- # ========== Settings Accessors (WebFetch and control) ==========
232
-
233
- # @!method webfetch_provider
234
- # Get the WebFetch LLM provider
235
- # @return [String, nil] The provider
236
- #
237
- # @!method allow_filesystem_tools
238
- # Get whether filesystem tools are allowed
239
- # @return [Boolean] true if allowed
240
-
241
- SETTINGS_MAPPINGS.each_key do |config_key|
242
- _env_key, default_value = SETTINGS_MAPPINGS[config_key]
243
-
244
- # Getter with default fallback
245
- define_method(config_key) do
246
- ensure_env_loaded!
247
- if @explicit_values.key?(config_key)
248
- @explicit_values[config_key]
249
- elsif @env_values.key?(config_key)
250
- @env_values[config_key]
251
- else
252
- default_value
253
- end
254
- end
255
-
256
- # Setter
257
- define_method("#{config_key}=") do |value|
258
- @explicit_values[config_key] = value
259
- end
260
- end
261
-
262
- # ========== Convenience Methods ==========
263
-
264
- # Check if WebFetch LLM processing is enabled
265
- #
266
- # WebFetch uses LLM processing when both provider and model are configured.
267
- #
268
- # @return [Boolean] true if WebFetch LLM is configured
269
- def webfetch_llm_enabled?
270
- !webfetch_provider.nil? && !webfetch_model.nil?
271
- end
272
-
273
- private
274
-
275
- # Ensure ENV values are loaded (lazy loading with double-check locking)
276
- #
277
- # Thread-safe lazy loading of ENV values. Only loads once per Config instance.
278
- #
279
- # @return [void]
280
- def ensure_env_loaded!
281
- return if @env_loaded
282
-
283
- @env_mutex.synchronize do
284
- return if @env_loaded
285
-
286
- load_env_values!
287
- @env_loaded = true
288
- end
289
- end
290
-
291
- # Load environment variable values
292
- #
293
- # Loads API keys (with RubyLLM proxying), defaults, and settings from ENV.
294
- # Only loads values that haven't been explicitly set.
295
- #
296
- # @return [void]
297
- def load_env_values!
298
- # Load API keys and proxy to RubyLLM
299
- API_KEY_MAPPINGS.each do |config_key, (ruby_llm_key, env_key)|
300
- next if @explicit_values.key?(config_key)
301
- next unless ENV.key?(env_key)
302
-
303
- value = ENV[env_key]
304
- @env_values[config_key] = value
305
-
306
- # Proxy to RubyLLM
307
- RubyLLM.config.public_send("#{ruby_llm_key}=", value)
308
- end
309
-
310
- # Load RubyLLM connection settings and proxy to RubyLLM
311
- RUBYLLM_CONNECTION_MAPPINGS.each do |config_key, (ruby_llm_key, env_key, _default)|
312
- next if @explicit_values.key?(config_key)
313
- next unless ENV.key?(env_key)
314
-
315
- value = parse_env_value(ENV[env_key], config_key)
316
- @env_values[config_key] = value
317
-
318
- # Proxy to RubyLLM
319
- RubyLLM.config.public_send("#{ruby_llm_key}=", value)
320
- end
321
-
322
- # Load defaults (no RubyLLM proxy)
323
- DEFAULTS_MAPPINGS.each do |config_key, (env_key, _default_proc)|
324
- next if @explicit_values.key?(config_key)
325
- next unless ENV.key?(env_key)
326
-
327
- @env_values[config_key] = parse_env_value(ENV[env_key], config_key)
328
- end
329
-
330
- # Load settings (no RubyLLM proxy)
331
- SETTINGS_MAPPINGS.each do |config_key, (env_key, _default_value)|
332
- next if @explicit_values.key?(config_key)
333
- next unless ENV.key?(env_key)
334
-
335
- @env_values[config_key] = parse_env_value(ENV[env_key], config_key)
336
- end
337
- end
338
-
339
- # Parse environment variable value to appropriate type
340
- #
341
- # Converts string ENV values to integers, floats, or booleans based on
342
- # the configuration key pattern.
343
- #
344
- # @param value [String] The ENV value string
345
- # @param key [Symbol] The configuration key
346
- # @return [Integer, Float, Boolean, String] The parsed value
347
- def parse_env_value(value, key)
348
- case key
349
- when :allow_filesystem_tools, :env_interpolation, :streaming, :mcp_ssl_verify
350
- # Convert string to boolean
351
- case value.to_s.downcase
352
- when "true", "yes", "1", "on", "enabled"
353
- true
354
- when "false", "no", "0", "off", "disabled"
355
- false
356
- else
357
- true # Default to true if unrecognized
358
- end
359
- when /_timeout$/, /_limit$/, /_interval$/, /_threshold$/, :mcp_log_level, :webfetch_max_tokens
360
- value.to_i
361
- when /^chars_per_token/
362
- value.to_f
363
- else
364
- value
365
- end
366
- end
367
- end
368
- end