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.
- checksums.yaml +4 -4
- data/lib/swarm_memory/version.rb +1 -1
- metadata +5 -184
- data/lib/claude_swarm/base_executor.rb +0 -133
- data/lib/claude_swarm/claude_code_executor.rb +0 -349
- data/lib/claude_swarm/claude_mcp_server.rb +0 -78
- data/lib/claude_swarm/cli.rb +0 -697
- data/lib/claude_swarm/commands/ps.rb +0 -215
- data/lib/claude_swarm/commands/show.rb +0 -139
- data/lib/claude_swarm/configuration.rb +0 -373
- data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
- data/lib/claude_swarm/json_handler.rb +0 -91
- data/lib/claude_swarm/mcp_generator.rb +0 -230
- data/lib/claude_swarm/openai/chat_completion.rb +0 -256
- data/lib/claude_swarm/openai/executor.rb +0 -256
- data/lib/claude_swarm/openai/responses.rb +0 -319
- data/lib/claude_swarm/orchestrator.rb +0 -878
- data/lib/claude_swarm/process_tracker.rb +0 -78
- data/lib/claude_swarm/session_cost_calculator.rb +0 -209
- data/lib/claude_swarm/session_path.rb +0 -42
- data/lib/claude_swarm/settings_generator.rb +0 -77
- data/lib/claude_swarm/system_utils.rb +0 -46
- data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
- data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
- data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
- data/lib/claude_swarm/tools/task_tool.rb +0 -63
- data/lib/claude_swarm/version.rb +0 -5
- data/lib/claude_swarm/worktree_manager.rb +0 -475
- data/lib/claude_swarm/yaml_loader.rb +0 -22
- data/lib/claude_swarm.rb +0 -67
- data/lib/swarm_cli/cli.rb +0 -201
- data/lib/swarm_cli/command_registry.rb +0 -61
- data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
- data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
- data/lib/swarm_cli/commands/migrate.rb +0 -55
- data/lib/swarm_cli/commands/run.rb +0 -173
- data/lib/swarm_cli/config_loader.rb +0 -98
- data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
- data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
- data/lib/swarm_cli/interactive_repl.rb +0 -924
- data/lib/swarm_cli/mcp_serve_options.rb +0 -44
- data/lib/swarm_cli/mcp_tools_options.rb +0 -59
- data/lib/swarm_cli/migrate_options.rb +0 -54
- data/lib/swarm_cli/migrator.rb +0 -132
- data/lib/swarm_cli/options.rb +0 -151
- data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
- data/lib/swarm_cli/ui/components/content_block.rb +0 -120
- data/lib/swarm_cli/ui/components/divider.rb +0 -57
- data/lib/swarm_cli/ui/components/panel.rb +0 -62
- data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
- data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
- data/lib/swarm_cli/ui/formatters/number.rb +0 -58
- data/lib/swarm_cli/ui/formatters/text.rb +0 -77
- data/lib/swarm_cli/ui/formatters/time.rb +0 -73
- data/lib/swarm_cli/ui/icons.rb +0 -36
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
- data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
- data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
- data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
- data/lib/swarm_cli/version.rb +0 -5
- data/lib/swarm_cli.rb +0 -46
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
- data/lib/swarm_sdk/agent/builder.rb +0 -552
- data/lib/swarm_sdk/agent/chat.rb +0 -774
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
- data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
- data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
- data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
- data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
- data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
- data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
- data/lib/swarm_sdk/agent/context.rb +0 -116
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -477
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/builders/base_builder.rb +0 -409
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
- data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
- data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
- data/lib/swarm_sdk/concerns/validatable.rb +0 -55
- data/lib/swarm_sdk/configuration/parser.rb +0 -353
- data/lib/swarm_sdk/configuration/translator.rb +0 -255
- data/lib/swarm_sdk/configuration.rb +0 -135
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
- data/lib/swarm_sdk/context_compactor.rb +0 -335
- data/lib/swarm_sdk/context_management/builder.rb +0 -128
- data/lib/swarm_sdk/context_management/context.rb +0 -328
- data/lib/swarm_sdk/defaults.rb +0 -196
- data/lib/swarm_sdk/events_to_messages.rb +0 -199
- data/lib/swarm_sdk/hooks/adapter.rb +0 -359
- data/lib/swarm_sdk/hooks/context.rb +0 -197
- data/lib/swarm_sdk/hooks/definition.rb +0 -80
- data/lib/swarm_sdk/hooks/error.rb +0 -29
- data/lib/swarm_sdk/hooks/executor.rb +0 -146
- data/lib/swarm_sdk/hooks/registry.rb +0 -147
- data/lib/swarm_sdk/hooks/result.rb +0 -150
- data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
- data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
- data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
- data/lib/swarm_sdk/log_collector.rb +0 -227
- data/lib/swarm_sdk/log_stream.rb +0 -127
- data/lib/swarm_sdk/markdown_parser.rb +0 -75
- data/lib/swarm_sdk/model_aliases.json +0 -8
- data/lib/swarm_sdk/models.json +0 -1
- data/lib/swarm_sdk/models.rb +0 -120
- data/lib/swarm_sdk/node_context.rb +0 -245
- data/lib/swarm_sdk/observer/builder.rb +0 -81
- data/lib/swarm_sdk/observer/config.rb +0 -45
- data/lib/swarm_sdk/observer/manager.rb +0 -236
- data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
- data/lib/swarm_sdk/permissions/config.rb +0 -239
- data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
- data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
- data/lib/swarm_sdk/permissions/validator.rb +0 -173
- data/lib/swarm_sdk/permissions_builder.rb +0 -122
- data/lib/swarm_sdk/plugin.rb +0 -309
- data/lib/swarm_sdk/plugin_registry.rb +0 -101
- data/lib/swarm_sdk/proc_helpers.rb +0 -53
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
- data/lib/swarm_sdk/restore_result.rb +0 -65
- data/lib/swarm_sdk/result.rb +0 -123
- data/lib/swarm_sdk/snapshot.rb +0 -156
- data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
- data/lib/swarm_sdk/state_restorer.rb +0 -476
- data/lib/swarm_sdk/state_snapshot.rb +0 -334
- data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
- data/lib/swarm_sdk/swarm/builder.rb +0 -249
- data/lib/swarm_sdk/swarm/executor.rb +0 -213
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
- data/lib/swarm_sdk/swarm.rb +0 -717
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/bash.rb +0 -282
- data/lib/swarm_sdk/tools/clock.rb +0 -44
- data/lib/swarm_sdk/tools/delegate.rb +0 -267
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
- data/lib/swarm_sdk/tools/edit.rb +0 -145
- data/lib/swarm_sdk/tools/glob.rb +0 -166
- data/lib/swarm_sdk/tools/grep.rb +0 -235
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
- data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
- data/lib/swarm_sdk/tools/read.rb +0 -261
- data/lib/swarm_sdk/tools/registry.rb +0 -205
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
- data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
- data/lib/swarm_sdk/tools/think.rb +0 -98
- data/lib/swarm_sdk/tools/todo_write.rb +0 -235
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/utils.rb +0 -68
- data/lib/swarm_sdk/validation_result.rb +0 -33
- data/lib/swarm_sdk/version.rb +0 -5
- data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
- data/lib/swarm_sdk/workflow/builder.rb +0 -143
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
- data/lib/swarm_sdk/workflow.rb +0 -554
- 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
|