swarm_memory 2.1.5 → 2.1.6

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. metadata +5 -184
  4. data/lib/claude_swarm/base_executor.rb +0 -133
  5. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  6. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  7. data/lib/claude_swarm/cli.rb +0 -697
  8. data/lib/claude_swarm/commands/ps.rb +0 -215
  9. data/lib/claude_swarm/commands/show.rb +0 -139
  10. data/lib/claude_swarm/configuration.rb +0 -373
  11. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  12. data/lib/claude_swarm/json_handler.rb +0 -91
  13. data/lib/claude_swarm/mcp_generator.rb +0 -230
  14. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  15. data/lib/claude_swarm/openai/executor.rb +0 -256
  16. data/lib/claude_swarm/openai/responses.rb +0 -319
  17. data/lib/claude_swarm/orchestrator.rb +0 -878
  18. data/lib/claude_swarm/process_tracker.rb +0 -78
  19. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  20. data/lib/claude_swarm/session_path.rb +0 -42
  21. data/lib/claude_swarm/settings_generator.rb +0 -77
  22. data/lib/claude_swarm/system_utils.rb +0 -46
  23. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  24. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  25. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  27. data/lib/claude_swarm/version.rb +0 -5
  28. data/lib/claude_swarm/worktree_manager.rb +0 -475
  29. data/lib/claude_swarm/yaml_loader.rb +0 -22
  30. data/lib/claude_swarm.rb +0 -67
  31. data/lib/swarm_cli/cli.rb +0 -201
  32. data/lib/swarm_cli/command_registry.rb +0 -61
  33. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  34. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  35. data/lib/swarm_cli/commands/migrate.rb +0 -55
  36. data/lib/swarm_cli/commands/run.rb +0 -173
  37. data/lib/swarm_cli/config_loader.rb +0 -98
  38. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  39. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  40. data/lib/swarm_cli/interactive_repl.rb +0 -924
  41. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  42. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  43. data/lib/swarm_cli/migrate_options.rb +0 -54
  44. data/lib/swarm_cli/migrator.rb +0 -132
  45. data/lib/swarm_cli/options.rb +0 -151
  46. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  47. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  48. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  49. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  50. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  51. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  52. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  53. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  54. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  55. data/lib/swarm_cli/ui/icons.rb +0 -36
  56. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  57. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  58. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  59. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  60. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  61. data/lib/swarm_cli/version.rb +0 -5
  62. data/lib/swarm_cli.rb +0 -46
  63. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  64. data/lib/swarm_sdk/agent/builder.rb +0 -552
  65. data/lib/swarm_sdk/agent/chat.rb +0 -774
  66. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  67. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  68. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  69. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  70. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  71. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  72. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  73. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  75. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  76. data/lib/swarm_sdk/agent/context.rb +0 -116
  77. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  78. data/lib/swarm_sdk/agent/definition.rb +0 -477
  79. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  80. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  81. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  82. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  83. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  84. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  85. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  86. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  87. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  88. data/lib/swarm_sdk/configuration.rb +0 -135
  89. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  90. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  91. data/lib/swarm_sdk/context_compactor.rb +0 -335
  92. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  93. data/lib/swarm_sdk/context_management/context.rb +0 -328
  94. data/lib/swarm_sdk/defaults.rb +0 -196
  95. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  96. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  97. data/lib/swarm_sdk/hooks/context.rb +0 -197
  98. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  99. data/lib/swarm_sdk/hooks/error.rb +0 -29
  100. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  101. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  102. data/lib/swarm_sdk/hooks/result.rb +0 -150
  103. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  104. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  105. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  106. data/lib/swarm_sdk/log_collector.rb +0 -227
  107. data/lib/swarm_sdk/log_stream.rb +0 -127
  108. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  109. data/lib/swarm_sdk/model_aliases.json +0 -8
  110. data/lib/swarm_sdk/models.json +0 -1
  111. data/lib/swarm_sdk/models.rb +0 -120
  112. data/lib/swarm_sdk/node_context.rb +0 -245
  113. data/lib/swarm_sdk/observer/builder.rb +0 -81
  114. data/lib/swarm_sdk/observer/config.rb +0 -45
  115. data/lib/swarm_sdk/observer/manager.rb +0 -236
  116. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  117. data/lib/swarm_sdk/permissions/config.rb +0 -239
  118. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  119. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  120. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  121. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  122. data/lib/swarm_sdk/plugin.rb +0 -309
  123. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  124. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  125. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  126. data/lib/swarm_sdk/restore_result.rb +0 -65
  127. data/lib/swarm_sdk/result.rb +0 -123
  128. data/lib/swarm_sdk/snapshot.rb +0 -156
  129. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  130. data/lib/swarm_sdk/state_restorer.rb +0 -476
  131. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  132. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  133. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  134. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  135. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  136. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  141. data/lib/swarm_sdk/swarm.rb +0 -717
  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/bash.rb +0 -282
  145. data/lib/swarm_sdk/tools/clock.rb +0 -44
  146. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  147. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  148. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  149. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  150. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  151. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  152. data/lib/swarm_sdk/tools/edit.rb +0 -145
  153. data/lib/swarm_sdk/tools/glob.rb +0 -166
  154. data/lib/swarm_sdk/tools/grep.rb +0 -235
  155. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  156. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  157. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  158. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  159. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  160. data/lib/swarm_sdk/tools/read.rb +0 -261
  161. data/lib/swarm_sdk/tools/registry.rb +0 -205
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  165. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  166. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  167. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  168. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  169. data/lib/swarm_sdk/tools/think.rb +0 -98
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/utils.rb +0 -68
  174. data/lib/swarm_sdk/validation_result.rb +0 -33
  175. data/lib/swarm_sdk/version.rb +0 -5
  176. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  177. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  178. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  179. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  180. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  181. data/lib/swarm_sdk/workflow.rb +0 -554
  182. data/lib/swarm_sdk.rb +0 -524
@@ -1,476 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # Restores swarm/workflow conversation state from snapshots
5
- #
6
- # Unified implementation that works for both Swarm and Workflow.
7
- # Validates compatibility between snapshot and current configuration,
8
- # restores conversation history, context state, scratchpad contents, and
9
- # read tracking information.
10
- #
11
- # Handles configuration mismatches gracefully by skipping agents that
12
- # don't exist in the current swarm/workflow and returning warnings in RestoreResult.
13
- #
14
- # ## System Prompt Handling
15
- #
16
- # By default, system prompts are taken from the **current YAML configuration**,
17
- # not from the snapshot. This makes configuration the source of truth and allows
18
- # you to update system prompts without creating new sessions.
19
- #
20
- # Set `preserve_system_prompts: true` to use historical prompts from the snapshot
21
- # (useful for debugging, auditing, or exact reproducibility).
22
- #
23
- # @example Restore with current system prompts (default)
24
- # swarm = SwarmSDK.build { ... }
25
- # snapshot_data = JSON.parse(File.read("session.json"), symbolize_names: true)
26
- # result = swarm.restore(snapshot_data)
27
- # # Uses system prompts from current YAML config
28
- #
29
- # @example Restore with historical system prompts
30
- # result = swarm.restore(snapshot_data, preserve_system_prompts: true)
31
- # # Uses system prompts that were active when snapshot was created
32
- class StateRestorer
33
- # Initialize state restorer
34
- #
35
- # @param orchestration [Swarm, Workflow] Swarm or workflow to restore into
36
- # @param snapshot [Snapshot, Hash, String] Snapshot object, hash, or JSON string
37
- # @param preserve_system_prompts [Boolean] If true, use system prompts from snapshot instead of current config (default: false)
38
- def initialize(orchestration, snapshot, preserve_system_prompts: false)
39
- @orchestration = orchestration
40
- @preserve_system_prompts = preserve_system_prompts
41
-
42
- # Handle different input types
43
- @snapshot_data = case snapshot
44
- when Snapshot
45
- snapshot.to_hash
46
- when String
47
- JSON.parse(snapshot, symbolize_names: true)
48
- when Hash
49
- snapshot
50
- else
51
- raise ArgumentError, "snapshot must be a Snapshot object, Hash, or JSON string"
52
- end
53
-
54
- validate_version!
55
- validate_type_match!
56
- end
57
-
58
- # Restore state from snapshot
59
- #
60
- # Three-phase process:
61
- # 1. Validate compatibility (which agents can be restored)
62
- # 2. Restore state (only for matched agents)
63
- # 3. Return result with warnings about skipped agents
64
- #
65
- # @return [RestoreResult] Result with warnings about partial restores
66
- def restore
67
- # Phase 1: Validate compatibility
68
- validation = validate_compatibility
69
-
70
- # Phase 2: Restore state (only for matched agents)
71
- restore_metadata
72
- restore_agent_conversations(validation.restorable_agents)
73
- restore_delegation_conversations(validation.restorable_delegations)
74
- restore_scratchpad
75
- restore_read_tracking
76
- restore_plugin_states
77
-
78
- # Phase 3: Return result with warnings
79
- SwarmSDK::RestoreResult.new(
80
- warnings: validation.warnings,
81
- skipped_agents: validation.skipped_agents,
82
- skipped_delegations: validation.skipped_delegations,
83
- )
84
- end
85
-
86
- private
87
-
88
- # Validate snapshot version
89
- #
90
- # @raise [StateError] if version is unsupported
91
- def validate_version!
92
- version = @snapshot_data[:version] || @snapshot_data["version"]
93
- unless version == "2.1.0"
94
- raise StateError, "Unsupported snapshot version: #{version}. Expected: 2.1.0"
95
- end
96
- end
97
-
98
- # Validate snapshot type matches orchestration type
99
- #
100
- # @raise [StateError] if types don't match
101
- def validate_type_match!
102
- snapshot_type = (@snapshot_data[:type] || @snapshot_data["type"]).to_s.downcase
103
- actual_type = @orchestration.class.name.split("::").last.downcase
104
-
105
- unless snapshot_type == actual_type
106
- raise StateError, "Snapshot type '#{snapshot_type}' doesn't match orchestration type '#{actual_type}'"
107
- end
108
- end
109
-
110
- # Validate compatibility between snapshot and current configuration
111
- #
112
- # @return [ValidationResult] Validation results
113
- def validate_compatibility
114
- warnings = []
115
- skipped_agents = []
116
- restorable_agents = []
117
- skipped_delegations = []
118
- restorable_delegations = []
119
-
120
- # Get current agent names from configuration
121
- current_agents = Set.new(@orchestration.agent_definitions.keys)
122
-
123
- # Check each snapshot agent
124
- snapshot_agents = @snapshot_data[:agents] || @snapshot_data["agents"]
125
- snapshot_agents.keys.each do |agent_name|
126
- agent_name_sym = agent_name.to_sym
127
-
128
- if current_agents.include?(agent_name_sym)
129
- restorable_agents << agent_name_sym
130
- else
131
- skipped_agents << agent_name_sym
132
- warnings << {
133
- type: :agent_not_found,
134
- agent: agent_name,
135
- message: "Agent '#{agent_name}' in snapshot not found in current configuration. " \
136
- "Conversation will not be restored.",
137
- }
138
- end
139
- end
140
-
141
- # Check delegation instances
142
- delegation_instances = @snapshot_data[:delegation_instances] || @snapshot_data["delegation_instances"]
143
- delegation_instances&.each do |instance_name, _data|
144
- base_name, delegator_name = instance_name.split("@")
145
-
146
- # Delegation can be restored if both agents exist in current configuration
147
- if current_agents.include?(base_name.to_sym) &&
148
- restorable_agents.include?(delegator_name.to_sym)
149
- restorable_delegations << instance_name
150
- else
151
- skipped_delegations << instance_name
152
- warnings << {
153
- type: :delegation_instance_not_restorable,
154
- instance: instance_name,
155
- message: "Delegation instance '#{instance_name}' cannot be restored " \
156
- "(base agent or delegator not in current swarm/workflow).",
157
- }
158
- end
159
- end
160
-
161
- SwarmSDK::ValidationResult.new(
162
- warnings: warnings,
163
- skipped_agents: skipped_agents,
164
- restorable_agents: restorable_agents,
165
- skipped_delegations: skipped_delegations,
166
- restorable_delegations: restorable_delegations,
167
- )
168
- end
169
-
170
- # Restore orchestration metadata
171
- #
172
- # @return [void]
173
- def restore_metadata
174
- # Restore metadata
175
- metadata = @snapshot_data[:metadata] || @snapshot_data["metadata"]
176
- return unless metadata
177
-
178
- # Restore first_message_sent flag (Swarm only, no-op for Workflow)
179
- if @orchestration.respond_to?(:first_message_sent=)
180
- first_sent = metadata[:first_message_sent] || metadata["first_message_sent"]
181
- @orchestration.first_message_sent = first_sent
182
- end
183
- end
184
-
185
- # Restore agent conversations
186
- #
187
- # Uses interface methods - no type checking!
188
- #
189
- # @param restorable_agents [Array<Symbol>] Agents that can be restored
190
- # @return [void]
191
- def restore_agent_conversations(restorable_agents)
192
- restorable_agents.each do |agent_name|
193
- # For Swarm: lazy initialization triggers when we call agent()
194
- # For Workflow: agents are in cache if already used, otherwise skip
195
- agent_chat = if @orchestration.is_a?(Swarm)
196
- @orchestration.agent(agent_name)
197
- else
198
- # Workflow: only restore if agent is already in cache
199
- @orchestration.primary_agents[agent_name]
200
- end
201
-
202
- next unless agent_chat
203
-
204
- # Get agent snapshot data
205
- agents_data = @snapshot_data[:agents] || @snapshot_data["agents"]
206
- snapshot_data = agents_data[agent_name] || agents_data[agent_name.to_s]
207
- next unless snapshot_data
208
-
209
- # Restore conversation
210
- restore_agent_conversation(agent_chat, agent_name, snapshot_data)
211
- end
212
- end
213
-
214
- # Restore a single agent's conversation
215
- #
216
- # @param agent_chat [Agent::Chat] Chat instance
217
- # @param agent_name [Symbol] Agent name
218
- # @param snapshot_data [Hash] Snapshot data for this agent
219
- # @return [void]
220
- def restore_agent_conversation(agent_chat, agent_name, snapshot_data)
221
- # Determine which system prompt to use
222
- system_prompt = if @preserve_system_prompts
223
- snapshot_data[:system_prompt] || snapshot_data["system_prompt"]
224
- else
225
- agent_definition = @orchestration.agent_definitions[agent_name]
226
- agent_definition&.system_prompt
227
- end
228
-
229
- # Build complete message list including system message
230
- all_messages = []
231
-
232
- # Add system message first if we have a system prompt
233
- if system_prompt
234
- all_messages << RubyLLM::Message.new(role: :system, content: system_prompt)
235
- end
236
-
237
- # Add conversation messages
238
- conversation = snapshot_data[:conversation] || snapshot_data["conversation"]
239
- restored_messages = conversation.map { |msg_data| deserialize_message(msg_data) }
240
- all_messages.concat(restored_messages)
241
-
242
- # Replace all messages using proper abstraction
243
- agent_chat.replace_messages(all_messages)
244
-
245
- # Restore context state
246
- context_state = snapshot_data[:context_state] || snapshot_data["context_state"]
247
- restore_context_state(agent_chat, context_state)
248
- end
249
-
250
- # Deserialize a message from snapshot data
251
- #
252
- # @param msg_data [Hash] Message data from snapshot
253
- # @return [RubyLLM::Message] Deserialized message
254
- def deserialize_message(msg_data)
255
- # Handle Content objects
256
- content = if msg_data[:content].is_a?(Hash) && (msg_data[:content].key?(:text) || msg_data[:content].key?("text"))
257
- content_data = msg_data[:content]
258
- text = content_data[:text] || content_data["text"]
259
- attachments = content_data[:attachments] || content_data["attachments"] || []
260
-
261
- RubyLLM::Content.new(text, attachments)
262
- else
263
- msg_data[:content]
264
- end
265
-
266
- # Handle tool calls
267
- tool_calls_hash = if msg_data[:tool_calls] && !msg_data[:tool_calls].empty?
268
- msg_data[:tool_calls].each_with_object({}) do |tc_data, hash|
269
- id = tc_data[:id] || tc_data["id"]
270
- name = tc_data[:name] || tc_data["name"]
271
- arguments = tc_data[:arguments] || tc_data["arguments"] || {}
272
-
273
- hash[id.to_s] = RubyLLM::ToolCall.new(
274
- id: id,
275
- name: name,
276
- arguments: arguments,
277
- )
278
- end
279
- end
280
-
281
- RubyLLM::Message.new(
282
- role: (msg_data[:role] || msg_data["role"]).to_sym,
283
- content: content,
284
- tool_calls: tool_calls_hash,
285
- tool_call_id: msg_data[:tool_call_id] || msg_data["tool_call_id"],
286
- input_tokens: msg_data[:input_tokens] || msg_data["input_tokens"],
287
- output_tokens: msg_data[:output_tokens] || msg_data["output_tokens"],
288
- model_id: msg_data[:model_id] || msg_data["model_id"],
289
- )
290
- end
291
-
292
- # Restore context state for an agent
293
- #
294
- # @param agent_chat [Agent::Chat] Agent chat instance
295
- # @param context_state [Hash] Context state data
296
- # @return [void]
297
- def restore_context_state(agent_chat, context_state)
298
- context_manager = agent_chat.context_manager
299
- agent_context = agent_chat.agent_context
300
-
301
- # Restore warning thresholds
302
- if context_state[:warning_thresholds_hit] || context_state["warning_thresholds_hit"]
303
- thresholds_array = context_state[:warning_thresholds_hit] || context_state["warning_thresholds_hit"]
304
- thresholds_set = agent_context.warning_thresholds_hit
305
- thresholds_array.each { |t| thresholds_set.add(t) }
306
- end
307
-
308
- # Restore compression flag
309
- compression = context_state[:compression_applied] || context_state["compression_applied"]
310
- context_manager.compression_applied = compression
311
-
312
- # Restore TodoWrite tracking
313
- todowrite_index = context_state[:last_todowrite_message_index] || context_state["last_todowrite_message_index"]
314
- agent_chat.last_todowrite_message_index = todowrite_index
315
-
316
- # Restore active skill path
317
- skill_path = context_state[:active_skill_path] || context_state["active_skill_path"]
318
- agent_chat.active_skill_path = skill_path
319
- end
320
-
321
- # Restore delegation instance conversations
322
- #
323
- # Uses interface methods - no type checking!
324
- #
325
- # @param restorable_delegations [Array<String>] Delegation instances that can be restored
326
- # @return [void]
327
- def restore_delegation_conversations(restorable_delegations)
328
- restorable_delegations.each do |instance_name|
329
- # Use interface method - works for both!
330
- delegation_chat = @orchestration.delegation_instances_hash[instance_name]
331
- next unless delegation_chat
332
-
333
- # Get delegation snapshot data
334
- delegations_data = @snapshot_data[:delegation_instances] || @snapshot_data["delegation_instances"]
335
- snapshot_data = delegations_data[instance_name.to_sym] || delegations_data[instance_name.to_s] || delegations_data[instance_name]
336
- next unless snapshot_data
337
-
338
- # Extract base agent name
339
- base_name = instance_name.to_s.split("@").first.to_sym
340
-
341
- # Restore conversation
342
- restore_delegation_conversation(delegation_chat, base_name, snapshot_data)
343
- end
344
- end
345
-
346
- # Restore a single delegation's conversation
347
- #
348
- # @param delegation_chat [Agent::Chat] Chat instance
349
- # @param base_name [Symbol] Base agent name
350
- # @param snapshot_data [Hash] Snapshot data
351
- # @return [void]
352
- def restore_delegation_conversation(delegation_chat, base_name, snapshot_data)
353
- # Determine which system prompt to use
354
- system_prompt = if @preserve_system_prompts
355
- snapshot_data[:system_prompt] || snapshot_data["system_prompt"]
356
- else
357
- agent_definition = @orchestration.agent_definitions[base_name]
358
- agent_definition&.system_prompt
359
- end
360
-
361
- # Build complete message list including system message
362
- all_messages = []
363
-
364
- # Add system message first if we have a system prompt
365
- if system_prompt
366
- all_messages << RubyLLM::Message.new(role: :system, content: system_prompt)
367
- end
368
-
369
- # Restore conversation messages
370
- conversation = snapshot_data[:conversation] || snapshot_data["conversation"]
371
- restored_messages = conversation.map { |msg_data| deserialize_message(msg_data) }
372
- all_messages.concat(restored_messages)
373
-
374
- # Replace all messages using proper abstraction
375
- delegation_chat.replace_messages(all_messages)
376
-
377
- # Restore context state
378
- context_state = snapshot_data[:context_state] || snapshot_data["context_state"]
379
- restore_context_state(delegation_chat, context_state)
380
- end
381
-
382
- # Restore scratchpad contents
383
- #
384
- # @return [void]
385
- def restore_scratchpad
386
- scratchpad_data = @snapshot_data[:scratchpad] || @snapshot_data["scratchpad"]
387
- return unless scratchpad_data&.any?
388
-
389
- if @orchestration.is_a?(Workflow)
390
- restore_workflow_scratchpad(scratchpad_data)
391
- else
392
- restore_swarm_scratchpad(scratchpad_data)
393
- end
394
- end
395
-
396
- # Restore scratchpad for Workflow
397
- #
398
- # @param scratchpad_data [Hash] { shared: bool, data: ... }
399
- # @return [void]
400
- def restore_workflow_scratchpad(scratchpad_data)
401
- snapshot_shared_mode = scratchpad_data[:shared] || scratchpad_data["shared"]
402
- data = scratchpad_data[:data] || scratchpad_data["data"]
403
-
404
- return unless data&.any?
405
-
406
- # Warn if snapshot mode doesn't match current configuration
407
- if snapshot_shared_mode != @orchestration.shared_scratchpad?
408
- RubyLLM.logger.warn(
409
- "SwarmSDK: Scratchpad mode mismatch: snapshot=#{snapshot_shared_mode ? "enabled" : "per_node"}, " \
410
- "current=#{@orchestration.shared_scratchpad? ? "enabled" : "per_node"}",
411
- )
412
- RubyLLM.logger.warn("SwarmSDK: Restoring anyway - data may not behave as expected")
413
- end
414
-
415
- if snapshot_shared_mode
416
- # Restore shared scratchpad
417
- shared_scratchpad = @orchestration.scratchpad_for(@orchestration.start_node)
418
- shared_scratchpad&.restore_entries(data)
419
- else
420
- # Restore per-node scratchpads
421
- data.each do |node_name, entries|
422
- next unless entries&.any?
423
-
424
- scratchpad = @orchestration.scratchpad_for(node_name.to_sym)
425
- scratchpad&.restore_entries(entries)
426
- end
427
- end
428
- end
429
-
430
- # Restore scratchpad for Swarm
431
- #
432
- # @param scratchpad_data [Hash] Flat scratchpad entries
433
- # @return [void]
434
- def restore_swarm_scratchpad(scratchpad_data)
435
- scratchpad = @orchestration.scratchpad_storage
436
- return unless scratchpad
437
-
438
- scratchpad.restore_entries(scratchpad_data)
439
- end
440
-
441
- # Restore read tracking state
442
- #
443
- # @return [void]
444
- def restore_read_tracking
445
- read_tracking_data = @snapshot_data[:read_tracking] || @snapshot_data["read_tracking"]
446
- return unless read_tracking_data
447
-
448
- read_tracking_data.each do |agent_name, files_with_digests|
449
- agent_sym = agent_name.to_sym
450
- Tools::Stores::ReadTracker.restore_read_files(agent_sym, files_with_digests)
451
- end
452
- end
453
-
454
- # Restore plugin-specific state for all plugins
455
- #
456
- # @return [void]
457
- def restore_plugin_states
458
- plugin_states_data = @snapshot_data[:plugin_states] || @snapshot_data["plugin_states"]
459
- return unless plugin_states_data
460
-
461
- plugin_states_data.each do |plugin_name, agents_state|
462
- # Find plugin by name
463
- plugin = PluginRegistry.all.find { |p| p.name.to_s == plugin_name.to_s }
464
- next unless plugin
465
-
466
- # Restore state for each agent
467
- agents_state.each do |agent_name, state|
468
- agent_sym = agent_name.to_sym
469
- # Symbolize keys for consistent access
470
- symbolized_state = state.is_a?(Hash) ? state.transform_keys(&:to_sym) : state
471
- plugin.restore_agent_state(agent_sym, symbolized_state)
472
- end
473
- end
474
- end
475
- end
476
- end