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
@@ -0,0 +1,330 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmSDK
4
+ module V3
5
+ # Immutable agent configuration
6
+ #
7
+ # Defines everything about an agent's identity, capabilities, and memory settings.
8
+ # Once created, a definition cannot be modified — create a new one instead.
9
+ #
10
+ # @example Minimal definition
11
+ # definition = AgentDefinition.new(
12
+ # name: :assistant,
13
+ # description: "A helpful assistant",
14
+ # )
15
+ #
16
+ # @example Full definition with memory
17
+ # definition = AgentDefinition.new(
18
+ # name: :researcher,
19
+ # description: "Research specialist",
20
+ # model: "claude-sonnet-4",
21
+ # system_prompt: "You are an expert researcher.",
22
+ # tools: [:Read, :Write, :Edit, :Bash, :Grep, :Glob],
23
+ # directory: "/path/to/project",
24
+ # parameters: { temperature: 0.7, thinking: { type: "enabled", budget_tokens: 10_000 } },
25
+ # headers: { "anthropic-beta" => "some-feature" },
26
+ # memory_directory: ".swarm/memory",
27
+ # memory_stm_turns: 8,
28
+ # memory_retrieval_top_k: 15,
29
+ # )
30
+ #
31
+ # @example Custom memory adapter
32
+ # definition = AgentDefinition.new(
33
+ # name: :assistant,
34
+ # description: "Assistant with Postgres memory",
35
+ # memory_adapter: PgvectorAdapter.new("postgres://localhost/myapp"),
36
+ # )
37
+ class AgentDefinition
38
+ # Valid API versions for OpenAI provider
39
+ VALID_API_VERSIONS = ["v1/responses", "v1/chat/completions"].freeze
40
+
41
+ # Valid queue delivery modes
42
+ VALID_QUEUE_MODES = [:all, :one_at_a_time].freeze
43
+
44
+ # @return [Symbol] Agent identifier
45
+ attr_reader :name
46
+
47
+ # @return [String] Agent role description
48
+ attr_reader :description
49
+
50
+ # @return [String] LLM model ID
51
+ attr_reader :model
52
+
53
+ # @return [String, nil] LLM provider
54
+ attr_reader :provider
55
+
56
+ # @return [String, nil] System prompt instructions
57
+ attr_reader :system_prompt
58
+
59
+ # @return [Array<Symbol>] Tool names
60
+ attr_reader :tools
61
+
62
+ # @return [String] Working directory
63
+ attr_reader :directory
64
+
65
+ # @return [String, nil] Custom API endpoint
66
+ attr_reader :base_url
67
+
68
+ # @return [Integer, nil] Maximum concurrent tool executions
69
+ attr_reader :max_concurrent_tools
70
+
71
+ # @return [Hash] Raw API body parameters (temperature, thinking, etc.)
72
+ attr_reader :parameters
73
+
74
+ # @return [Hash] Raw HTTP headers
75
+ attr_reader :headers
76
+
77
+ # @return [String, nil] Filesystem adapter path (nil = no memory)
78
+ attr_reader :memory_directory
79
+
80
+ # @return [Memory::Adapters::Base, nil] Custom adapter instance
81
+ attr_reader :memory_adapter
82
+
83
+ # @return [Integer] Recent turns to keep in short-term memory
84
+ attr_reader :memory_stm_turns
85
+
86
+ # @return [Integer] Cards to retrieve per turn
87
+ attr_reader :memory_retrieval_top_k
88
+
89
+ # @return [Float] Hybrid search semantic weight (0.0-1.0)
90
+ attr_reader :memory_semantic_weight
91
+
92
+ # @return [Float] Hybrid search keyword weight (0.0-1.0)
93
+ attr_reader :memory_keyword_weight
94
+
95
+ # @return [Boolean] Whether to surface exploration cards as tangential memories
96
+ # the agent is encouraged to naturally bring up in conversation
97
+ attr_reader :memory_associative
98
+
99
+ # @return [Array<String>] Skill directory paths (expanded, frozen)
100
+ attr_reader :skills
101
+
102
+ # @return [Array<V3::MCP::ServerDefinition>] MCP server configurations (frozen)
103
+ attr_reader :mcp_servers
104
+
105
+ # @return [Hash, Object, nil] JSON Schema for structured output (pass-through to RubyLLM)
106
+ attr_reader :output_schema
107
+
108
+ # @return [String, nil] API version for OpenAI provider ("v1/responses" or "v1/chat/completions").
109
+ # Defaults to "v1/responses" when provider is "openai". nil for non-OpenAI providers.
110
+ attr_reader :api_version
111
+
112
+ # @return [Array<Hash>] Hook configurations (frozen). Each hash has :event, :block,
113
+ # and optional :match keys. Opaque to the definition — {Hooks::Runner} interprets them.
114
+ attr_reader :hooks
115
+
116
+ # @return [Symbol] Steering queue delivery mode (:all or :one_at_a_time)
117
+ attr_reader :steering_mode
118
+
119
+ # --- Subtask model configuration (per-agent override) ---
120
+
121
+ # @return [String, nil] Model for this agent's subtasks (nil = use global config or inherit)
122
+ attr_reader :subtask_model
123
+
124
+ # @return [String, nil] Provider for subtask model
125
+ attr_reader :subtask_provider
126
+
127
+ # @return [String, nil] Custom API base URL for subtask model
128
+ attr_reader :subtask_base_url
129
+
130
+ # @return [Hash] Custom HTTP headers for subtask model
131
+ attr_reader :subtask_headers
132
+
133
+ # @return [Hash] Raw API body parameters for subtask model
134
+ attr_reader :subtask_parameters
135
+
136
+ # Create a new agent definition
137
+ #
138
+ # @param name [Symbol, String] Agent identifier (required)
139
+ # @param description [String] Agent role description (required)
140
+ # @param model [String, nil] LLM model ID
141
+ # @param provider [String, nil] LLM provider
142
+ # @param system_prompt [String, nil] System prompt instructions
143
+ # @param tools [Array<Symbol>] Tool names
144
+ # @param directory [String] Working directory
145
+ # @param base_url [String, nil] Custom API endpoint
146
+ # @param max_concurrent_tools [Integer, nil] Max concurrent tool executions
147
+ # @param parameters [Hash] Raw API body parameters
148
+ # @param headers [Hash] Raw HTTP headers
149
+ # @param memory_directory [String, nil] Filesystem adapter path
150
+ # @param memory_adapter [Memory::Adapters::Base, nil] Custom adapter instance
151
+ # @param memory_stm_turns [Integer] Recent turns in STM
152
+ # @param memory_retrieval_top_k [Integer] Cards to retrieve per turn
153
+ # @param memory_semantic_weight [Float] Semantic search weight
154
+ # @param memory_keyword_weight [Float] Keyword search weight
155
+ # @param memory_associative [Boolean, nil] Enable associative memory
156
+ # @param skills [Array<String>] Skill directory paths
157
+ # @param mcp_servers [Array<Hash, V3::MCP::ServerDefinition>] MCP server configurations
158
+ # @param output_schema [Hash, Object, nil] JSON Schema for structured output (pass-through to RubyLLM)
159
+ # @param api_version [String, nil] API version for OpenAI provider.
160
+ # Valid values: "v1/responses", "v1/chat/completions".
161
+ # Defaults to "v1/responses" when provider is "openai". Ignored for other providers.
162
+ # @param hooks [Array<Hash>] Hook configurations. Each hash has :event (Symbol),
163
+ # :block (Proc), and optional :match keys. See {Hooks::Runner} for details.
164
+ # @param steering_mode [Symbol] Steering queue delivery mode (:all or :one_at_a_time).
165
+ # Default: :all (all steering messages injected together).
166
+ # @param subtask_model [String, nil] Model for this agent's subtasks
167
+ # @param subtask_provider [String, nil] Provider for subtask model
168
+ # @param subtask_base_url [String, nil] Custom API base URL for subtask model
169
+ # @param subtask_headers [Hash] Custom HTTP headers for subtask model
170
+ # @param subtask_parameters [Hash] Raw API body parameters for subtask model
171
+ #
172
+ # @raise [ConfigurationError] If required fields are missing or invalid
173
+ def initialize(
174
+ name:,
175
+ description:,
176
+ model: nil,
177
+ provider: nil,
178
+ system_prompt: nil,
179
+ tools: [],
180
+ directory: ".",
181
+ base_url: nil,
182
+ max_concurrent_tools: nil,
183
+ parameters: {},
184
+ headers: {},
185
+ memory_directory: nil,
186
+ memory_adapter: nil,
187
+ memory_stm_turns: nil,
188
+ memory_retrieval_top_k: nil,
189
+ memory_semantic_weight: nil,
190
+ memory_keyword_weight: nil,
191
+ memory_associative: nil,
192
+ skills: [],
193
+ mcp_servers: [],
194
+ output_schema: nil,
195
+ api_version: nil,
196
+ hooks: [],
197
+ steering_mode: :all,
198
+ subtask_model: nil,
199
+ subtask_provider: nil,
200
+ subtask_base_url: nil,
201
+ subtask_headers: {},
202
+ subtask_parameters: {}
203
+ )
204
+ config = Configuration.instance
205
+
206
+ @name = name.to_sym
207
+ @description = description
208
+ @model = model || config.default_model
209
+ @provider = provider
210
+ @system_prompt = system_prompt
211
+ @tools = Array(tools).map(&:to_sym)
212
+ @directory = File.expand_path(directory)
213
+ @base_url = base_url
214
+ @max_concurrent_tools = max_concurrent_tools || config.default_max_concurrent_tools
215
+ @parameters = parameters.freeze
216
+ @headers = headers.freeze
217
+ @memory_directory = memory_directory
218
+ @memory_adapter = memory_adapter
219
+ @memory_stm_turns = memory_stm_turns || config.default_stm_turns
220
+ @memory_retrieval_top_k = memory_retrieval_top_k || config.default_retrieval_top_k
221
+ @memory_semantic_weight = memory_semantic_weight || config.default_semantic_weight
222
+ @memory_keyword_weight = memory_keyword_weight || config.default_keyword_weight
223
+ @memory_associative = memory_associative.nil? ? config.default_associative_memory : memory_associative
224
+ @skills = Array(skills).map { |s| File.expand_path(s) }.freeze
225
+ @mcp_servers = Array(mcp_servers).map do |config|
226
+ config.is_a?(V3::MCP::ServerDefinition) ? config : V3::MCP::ServerDefinition.new(**config)
227
+ end.freeze
228
+ @output_schema = output_schema
229
+ @api_version = resolve_api_version(api_version)
230
+ @hooks = Array(hooks).freeze
231
+ @steering_mode = steering_mode.to_sym
232
+ @subtask_model = subtask_model
233
+ @subtask_provider = subtask_provider
234
+ @subtask_base_url = subtask_base_url
235
+ @subtask_headers = subtask_headers.freeze
236
+ @subtask_parameters = subtask_parameters.freeze
237
+
238
+ validate!
239
+ freeze
240
+ end
241
+
242
+ # Whether this agent has memory enabled
243
+ #
244
+ # @return [Boolean] true if memory_directory or memory_adapter is set
245
+ def memory_enabled?
246
+ !@memory_directory.nil? || !@memory_adapter.nil?
247
+ end
248
+
249
+ # Whether this agent has subtask model configuration
250
+ #
251
+ # @return [Boolean] true if any subtask_* option is set
252
+ def subtask_config?
253
+ !@subtask_model.nil? ||
254
+ !@subtask_provider.nil? ||
255
+ !@subtask_base_url.nil? ||
256
+ !@subtask_headers.empty? ||
257
+ !@subtask_parameters.empty?
258
+ end
259
+
260
+ private
261
+
262
+ # Resolve the effective API version based on provider
263
+ #
264
+ # When provider is "openai" and no api_version is specified,
265
+ # defaults to "v1/responses" (OpenAI Responses API).
266
+ #
267
+ # @param explicit_version [String, nil] Explicitly set api_version
268
+ # @return [String, nil] Resolved API version
269
+ def resolve_api_version(explicit_version)
270
+ openai = @provider.to_s.downcase == "openai"
271
+
272
+ if explicit_version
273
+ return explicit_version if openai
274
+
275
+ raise ConfigurationError,
276
+ "api_version is only supported for the OpenAI provider (got provider: #{@provider.inspect})"
277
+ end
278
+
279
+ openai ? "v1/responses" : nil
280
+ end
281
+
282
+ # Validate the definition
283
+ #
284
+ # @raise [ConfigurationError] If validation fails
285
+ def validate!
286
+ raise ConfigurationError, "Agent name is required" if @name.nil? || @name.to_s.strip.empty?
287
+ raise ConfigurationError, "Agent description is required" if @description.nil? || @description.to_s.strip.empty?
288
+ raise ConfigurationError, "Agent model is required" if @model.nil? || @model.to_s.strip.empty?
289
+
290
+ if @api_version && !VALID_API_VERSIONS.include?(@api_version)
291
+ raise ConfigurationError,
292
+ "Invalid api_version #{@api_version.inspect}. " \
293
+ "Valid values: #{VALID_API_VERSIONS.map(&:inspect).join(", ")}"
294
+ end
295
+
296
+ if @memory_semantic_weight < 0.0 || @memory_semantic_weight > 1.0
297
+ raise ConfigurationError, "memory_semantic_weight must be between 0.0 and 1.0"
298
+ end
299
+
300
+ if @memory_keyword_weight < 0.0 || @memory_keyword_weight > 1.0
301
+ raise ConfigurationError, "memory_keyword_weight must be between 0.0 and 1.0"
302
+ end
303
+
304
+ if @memory_stm_turns < 1
305
+ raise ConfigurationError, "memory_stm_turns must be at least 1"
306
+ end
307
+
308
+ if @memory_retrieval_top_k < 1
309
+ raise ConfigurationError, "memory_retrieval_top_k must be at least 1"
310
+ end
311
+
312
+ if @skills.any? && !@tools.include?(:Read)
313
+ raise ConfigurationError, "Agent with skills requires the Read tool to activate skills"
314
+ end
315
+
316
+ unless VALID_QUEUE_MODES.include?(@steering_mode)
317
+ raise ConfigurationError,
318
+ "Invalid steering_mode #{@steering_mode.inspect}. " \
319
+ "Valid values: #{VALID_QUEUE_MODES.map(&:inspect).join(", ")}"
320
+ end
321
+
322
+ if subtask_config? && !@tools.include?(:SubTask)
323
+ raise ConfigurationError,
324
+ "Agent '#{@name}' has subtask model configuration but does not include the :SubTask tool. " \
325
+ "Either add :SubTask to tools or remove subtask_* options."
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end