swarm_sdk 2.7.13 → 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.
- checksums.yaml +4 -4
- data/lib/swarm_sdk/ruby_llm_patches/chat_callbacks_patch.rb +43 -22
- data/lib/swarm_sdk/ruby_llm_patches/init.rb +6 -0
- data/lib/swarm_sdk/ruby_llm_patches/mcp_ssl_patch.rb +144 -0
- data/lib/swarm_sdk/ruby_llm_patches/tool_concurrency_patch.rb +3 -4
- data/lib/swarm_sdk/v3/agent.rb +1165 -0
- data/lib/swarm_sdk/v3/agent_builder.rb +533 -0
- data/lib/swarm_sdk/v3/agent_definition.rb +330 -0
- data/lib/swarm_sdk/v3/configuration.rb +490 -0
- data/lib/swarm_sdk/v3/debug_log.rb +86 -0
- data/lib/swarm_sdk/v3/event_stream.rb +130 -0
- data/lib/swarm_sdk/v3/hooks/context.rb +112 -0
- data/lib/swarm_sdk/v3/hooks/result.rb +115 -0
- data/lib/swarm_sdk/v3/hooks/runner.rb +128 -0
- data/lib/swarm_sdk/v3/mcp/connector.rb +183 -0
- data/lib/swarm_sdk/v3/mcp/mcp_error.rb +15 -0
- data/lib/swarm_sdk/v3/mcp/server_definition.rb +125 -0
- data/lib/swarm_sdk/v3/mcp/ssl_http_transport.rb +103 -0
- data/lib/swarm_sdk/v3/mcp/stdio_transport.rb +135 -0
- data/lib/swarm_sdk/v3/mcp/tool_proxy.rb +53 -0
- data/lib/swarm_sdk/v3/memory/adapters/base.rb +297 -0
- data/lib/swarm_sdk/v3/memory/adapters/faiss_support.rb +194 -0
- data/lib/swarm_sdk/v3/memory/adapters/filesystem_adapter.rb +212 -0
- data/lib/swarm_sdk/v3/memory/adapters/sqlite_adapter.rb +507 -0
- data/lib/swarm_sdk/v3/memory/adapters/vector_utils.rb +88 -0
- data/lib/swarm_sdk/v3/memory/card.rb +206 -0
- data/lib/swarm_sdk/v3/memory/cluster.rb +146 -0
- data/lib/swarm_sdk/v3/memory/compressor.rb +496 -0
- data/lib/swarm_sdk/v3/memory/consolidator.rb +427 -0
- data/lib/swarm_sdk/v3/memory/context_builder.rb +339 -0
- data/lib/swarm_sdk/v3/memory/edge.rb +105 -0
- data/lib/swarm_sdk/v3/memory/embedder.rb +185 -0
- data/lib/swarm_sdk/v3/memory/exposure_tracker.rb +104 -0
- data/lib/swarm_sdk/v3/memory/ingestion_pipeline.rb +394 -0
- data/lib/swarm_sdk/v3/memory/retriever.rb +289 -0
- data/lib/swarm_sdk/v3/memory/store.rb +489 -0
- data/lib/swarm_sdk/v3/skills/loader.rb +147 -0
- data/lib/swarm_sdk/v3/skills/manifest.rb +45 -0
- data/lib/swarm_sdk/v3/sub_task_agent.rb +248 -0
- data/lib/swarm_sdk/v3/tools/base.rb +80 -0
- data/lib/swarm_sdk/v3/tools/bash.rb +174 -0
- data/lib/swarm_sdk/v3/tools/clock.rb +32 -0
- data/lib/swarm_sdk/v3/tools/edit.rb +111 -0
- data/lib/swarm_sdk/v3/tools/glob.rb +96 -0
- data/lib/swarm_sdk/v3/tools/grep.rb +200 -0
- data/lib/swarm_sdk/v3/tools/message_teammate.rb +15 -0
- data/lib/swarm_sdk/v3/tools/message_user.rb +15 -0
- data/lib/swarm_sdk/v3/tools/read.rb +181 -0
- data/lib/swarm_sdk/v3/tools/read_tracker.rb +40 -0
- data/lib/swarm_sdk/v3/tools/registry.rb +208 -0
- data/lib/swarm_sdk/v3/tools/sub_task.rb +183 -0
- data/lib/swarm_sdk/v3/tools/think.rb +88 -0
- data/lib/swarm_sdk/v3/tools/write.rb +87 -0
- data/lib/swarm_sdk/v3.rb +145 -0
- metadata +84 -148
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -175
- data/lib/swarm_sdk/agent/builder.rb +0 -680
- data/lib/swarm_sdk/agent/chat.rb +0 -1432
- data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -375
- 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 -85
- data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -290
- 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 -134
- data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
- data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -146
- data/lib/swarm_sdk/agent/context.rb +0 -115
- data/lib/swarm_sdk/agent/context_manager.rb +0 -315
- data/lib/swarm_sdk/agent/definition.rb +0 -581
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -226
- data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
- data/lib/swarm_sdk/agent/tool_registry.rb +0 -189
- data/lib/swarm_sdk/agent_registry.rb +0 -146
- data/lib/swarm_sdk/builders/base_builder.rb +0 -553
- 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/config.rb +0 -367
- data/lib/swarm_sdk/configuration/parser.rb +0 -397
- data/lib/swarm_sdk/configuration/translator.rb +0 -283
- data/lib/swarm_sdk/configuration.rb +0 -165
- data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
- data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -102
- 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/custom_tool_registry.rb +0 -226
- data/lib/swarm_sdk/defaults.rb +0 -251
- 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 -256
- 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 -44002
- data/lib/swarm_sdk/models.rb +0 -161
- 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 -212
- 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 -648
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -195
- data/lib/swarm_sdk/swarm/builder.rb +0 -256
- data/lib/swarm_sdk/swarm/executor.rb +0 -290
- data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -151
- data/lib/swarm_sdk/swarm/lazy_delegate_chat.rb +0 -372
- data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -360
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -270
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
- data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -392
- data/lib/swarm_sdk/swarm.rb +0 -843
- data/lib/swarm_sdk/swarm_loader.rb +0 -145
- data/lib/swarm_sdk/swarm_registry.rb +0 -136
- data/lib/swarm_sdk/tools/base.rb +0 -63
- data/lib/swarm_sdk/tools/bash.rb +0 -280
- data/lib/swarm_sdk/tools/clock.rb +0 -46
- data/lib/swarm_sdk/tools/delegate.rb +0 -389
- 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 -167
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
- data/lib/swarm_sdk/tools/mcp_tool_stub.rb +0 -198
- 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 -273
- 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 -100
- data/lib/swarm_sdk/tools/todo_write.rb +0 -237
- data/lib/swarm_sdk/tools/web_fetch.rb +0 -264
- data/lib/swarm_sdk/tools/write.rb +0 -112
- data/lib/swarm_sdk/transcript_builder.rb +0 -278
- 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 -95
- data/lib/swarm_sdk/workflow/builder.rb +0 -227
- data/lib/swarm_sdk/workflow/executor.rb +0 -497
- data/lib/swarm_sdk/workflow/node_builder.rb +0 -593
- data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -250
- data/lib/swarm_sdk/workflow.rb +0 -589
- data/lib/swarm_sdk.rb +0 -718
data/lib/swarm_sdk/result.rb
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SwarmSDK
|
|
4
|
-
class Result
|
|
5
|
-
attr_reader :content, :agent, :duration, :logs, :error, :metadata
|
|
6
|
-
|
|
7
|
-
def initialize(content: nil, agent:, cost: nil, tokens: nil, duration: 0.0, logs: [], error: nil, metadata: {})
|
|
8
|
-
@content = content
|
|
9
|
-
@agent = agent
|
|
10
|
-
@duration = duration
|
|
11
|
-
@logs = logs
|
|
12
|
-
@error = error
|
|
13
|
-
@metadata = metadata
|
|
14
|
-
# Legacy parameters kept for backward compatibility but not stored
|
|
15
|
-
# Use total_cost and tokens methods instead which calculate from logs
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def success?
|
|
19
|
-
@error.nil?
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def failure?
|
|
23
|
-
!success?
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Calculate total cost from logs
|
|
27
|
-
#
|
|
28
|
-
# Delegates to total_cost for consistency. This attribute is calculated
|
|
29
|
-
# dynamically rather than stored.
|
|
30
|
-
#
|
|
31
|
-
# @return [Float] Total cost in dollars
|
|
32
|
-
def cost
|
|
33
|
-
total_cost
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Get token breakdown from logs
|
|
37
|
-
#
|
|
38
|
-
# Returns input and output tokens from the last log entry with usage data.
|
|
39
|
-
# This attribute is calculated dynamically rather than stored.
|
|
40
|
-
#
|
|
41
|
-
# @return [Hash] Token breakdown with :input and :output keys, or empty hash if no usage data
|
|
42
|
-
def tokens
|
|
43
|
-
last_entry = @logs.reverse.find { |entry| entry.dig(:usage, :cumulative_input_tokens) }
|
|
44
|
-
return {} unless last_entry
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
input: last_entry.dig(:usage, :cumulative_input_tokens) || 0,
|
|
48
|
-
output: last_entry.dig(:usage, :cumulative_output_tokens) || 0,
|
|
49
|
-
}
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def to_h
|
|
53
|
-
{
|
|
54
|
-
content: @content,
|
|
55
|
-
agent: @agent,
|
|
56
|
-
cost: cost,
|
|
57
|
-
tokens: tokens,
|
|
58
|
-
duration: @duration,
|
|
59
|
-
success: success?,
|
|
60
|
-
error: @error&.message,
|
|
61
|
-
metadata: @metadata,
|
|
62
|
-
}.compact
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def to_json(*args)
|
|
66
|
-
to_h.to_json(*args)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Calculate total cost across all LLM responses
|
|
70
|
-
#
|
|
71
|
-
# Cost accumulation works as follows:
|
|
72
|
-
# - Input cost: The LAST response's input_cost already includes the cost for the
|
|
73
|
-
# full conversation history (all previous messages + current context)
|
|
74
|
-
# - Output cost: Each response generates NEW tokens, so we SUM all output_costs
|
|
75
|
-
# - Total = Last input_cost + Sum of all output_costs
|
|
76
|
-
#
|
|
77
|
-
# IMPORTANT: Do NOT sum total_cost across all entries - that would count
|
|
78
|
-
# input costs multiple times since each call includes the full history!
|
|
79
|
-
def total_cost
|
|
80
|
-
entries_with_usage = @logs.select { |entry| entry.dig(:usage, :total_cost) }
|
|
81
|
-
return 0.0 if entries_with_usage.empty?
|
|
82
|
-
|
|
83
|
-
# Last entry's input cost (includes full conversation history)
|
|
84
|
-
last_input_cost = entries_with_usage.last.dig(:usage, :input_cost) || 0.0
|
|
85
|
-
|
|
86
|
-
# Sum all output costs (each response generates new tokens)
|
|
87
|
-
total_output_cost = entries_with_usage.sum { |entry| entry.dig(:usage, :output_cost) || 0.0 }
|
|
88
|
-
|
|
89
|
-
last_input_cost + total_output_cost
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Get total tokens from the last LLM response with cumulative tracking
|
|
93
|
-
#
|
|
94
|
-
# Token accumulation works as follows:
|
|
95
|
-
# - Input tokens: Each API call sends the full conversation history, so the latest
|
|
96
|
-
# response's cumulative_input_tokens already represents the full context
|
|
97
|
-
# - Output tokens: Each response generates new tokens, cumulative_output_tokens sums them
|
|
98
|
-
# - The cumulative_total_tokens in the last response already does this correctly
|
|
99
|
-
#
|
|
100
|
-
# IMPORTANT: Do NOT sum total_tokens across all log entries - that would count
|
|
101
|
-
# input tokens multiple times since each call includes the full history!
|
|
102
|
-
def total_tokens
|
|
103
|
-
last_entry = @logs.reverse.find { |entry| entry.dig(:usage, :cumulative_total_tokens) }
|
|
104
|
-
last_entry&.dig(:usage, :cumulative_total_tokens) || 0
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Get list of all agents involved in execution
|
|
108
|
-
def agents_involved
|
|
109
|
-
@logs.map { |entry| entry[:agent] }.compact.uniq.map(&:to_sym)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Generate an LLM-readable transcript of the conversation
|
|
113
|
-
#
|
|
114
|
-
# Converts the execution logs into a human/LLM-readable format suitable for
|
|
115
|
-
# reflection, analysis, memory creation, or passing to another agent.
|
|
116
|
-
#
|
|
117
|
-
# @param agents [Array<Symbol>] Optional list of agents to filter by.
|
|
118
|
-
# If no agents specified, includes all agents.
|
|
119
|
-
# If one or more agents specified, only includes events from those agents.
|
|
120
|
-
# @param include_tool_results [Boolean] Include tool execution results (default: true)
|
|
121
|
-
# @param include_thinking [Boolean] Include agent_step content/thinking (default: false)
|
|
122
|
-
# @return [String] Formatted transcript ready for LLM consumption
|
|
123
|
-
#
|
|
124
|
-
# @example Get full transcript
|
|
125
|
-
# result.transcript
|
|
126
|
-
# # => "USER: Help me with CORS\n\nAGENT [assistant]: ..."
|
|
127
|
-
#
|
|
128
|
-
# @example Filter to specific agents
|
|
129
|
-
# result.transcript(:backend, :database)
|
|
130
|
-
# # => Only events from backend and database agents
|
|
131
|
-
#
|
|
132
|
-
# @example Single agent transcript
|
|
133
|
-
# result.transcript(:backend)
|
|
134
|
-
# # => Only events from backend agent
|
|
135
|
-
#
|
|
136
|
-
# @example Include thinking steps
|
|
137
|
-
# result.transcript(include_thinking: true)
|
|
138
|
-
# # => Includes agent_step intermediate reasoning
|
|
139
|
-
def transcript(*agents, include_tool_results: true, include_thinking: false)
|
|
140
|
-
agent_filter = agents.empty? ? nil : agents
|
|
141
|
-
TranscriptBuilder.build(
|
|
142
|
-
@logs,
|
|
143
|
-
agents: agent_filter,
|
|
144
|
-
include_tool_results: include_tool_results,
|
|
145
|
-
include_thinking: include_thinking,
|
|
146
|
-
)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Get per-agent usage breakdown from logs
|
|
150
|
-
#
|
|
151
|
-
# Aggregates context usage, tokens, and cost for each agent from their
|
|
152
|
-
# final agent_stop or agent_step events. Each agent's entry includes:
|
|
153
|
-
# - input_tokens, output_tokens, total_tokens
|
|
154
|
-
# - context_limit, usage_percentage, tokens_remaining
|
|
155
|
-
# - input_cost, output_cost, total_cost
|
|
156
|
-
#
|
|
157
|
-
# @return [Hash{Symbol => Hash}] Per-agent usage breakdown
|
|
158
|
-
#
|
|
159
|
-
# @example
|
|
160
|
-
# result.per_agent_usage[:backend]
|
|
161
|
-
# # => {
|
|
162
|
-
# # input_tokens: 15000,
|
|
163
|
-
# # output_tokens: 5000,
|
|
164
|
-
# # total_tokens: 20000,
|
|
165
|
-
# # context_limit: 200000,
|
|
166
|
-
# # usage_percentage: "10.0%",
|
|
167
|
-
# # tokens_remaining: 180000,
|
|
168
|
-
# # input_cost: 0.045,
|
|
169
|
-
# # output_cost: 0.075,
|
|
170
|
-
# # total_cost: 0.12
|
|
171
|
-
# # }
|
|
172
|
-
def per_agent_usage
|
|
173
|
-
# Find the last usage entry for each agent
|
|
174
|
-
agent_entries = {}
|
|
175
|
-
|
|
176
|
-
@logs.each do |entry|
|
|
177
|
-
next unless entry[:usage] && entry[:agent]
|
|
178
|
-
next unless entry[:type] == "agent_step" || entry[:type] == "agent_stop"
|
|
179
|
-
|
|
180
|
-
agent_name = entry[:agent].to_sym
|
|
181
|
-
agent_entries[agent_name] = entry[:usage]
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Build breakdown from final usage entries
|
|
185
|
-
agent_entries.transform_values do |usage|
|
|
186
|
-
{
|
|
187
|
-
input_tokens: usage[:cumulative_input_tokens] || 0,
|
|
188
|
-
output_tokens: usage[:cumulative_output_tokens] || 0,
|
|
189
|
-
total_tokens: usage[:cumulative_total_tokens] || 0,
|
|
190
|
-
cached_tokens: usage[:cumulative_cached_tokens] || 0,
|
|
191
|
-
context_limit: usage[:context_limit],
|
|
192
|
-
usage_percentage: usage[:tokens_used_percentage],
|
|
193
|
-
tokens_remaining: usage[:tokens_remaining],
|
|
194
|
-
input_cost: usage[:input_cost] || 0.0,
|
|
195
|
-
output_cost: usage[:output_cost] || 0.0,
|
|
196
|
-
total_cost: usage[:total_cost] || 0.0,
|
|
197
|
-
}
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Count total LLM requests made
|
|
202
|
-
# Each LLM API call produces either agent_step (tool calls) or agent_stop (final answer)
|
|
203
|
-
def llm_requests
|
|
204
|
-
@logs.count { |entry| entry[:type] == "agent_step" || entry[:type] == "agent_stop" }
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
# Count total tool calls made
|
|
208
|
-
def tool_calls_count
|
|
209
|
-
@logs.count { |entry| entry[:type] == "tool_call" }
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
end
|
data/lib/swarm_sdk/snapshot.rb
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SwarmSDK
|
|
4
|
-
# Snapshot of swarm conversation state
|
|
5
|
-
#
|
|
6
|
-
# Encapsulates snapshot data with methods for serialization and deserialization.
|
|
7
|
-
# Provides a clean API for saving/loading snapshots in various formats.
|
|
8
|
-
#
|
|
9
|
-
# @example Create and save snapshot
|
|
10
|
-
# snapshot = swarm.snapshot
|
|
11
|
-
# snapshot.write_to_file("session.json")
|
|
12
|
-
#
|
|
13
|
-
# @example Load and restore snapshot
|
|
14
|
-
# snapshot = SwarmSDK::Snapshot.from_file("session.json")
|
|
15
|
-
# result = swarm.restore(snapshot)
|
|
16
|
-
#
|
|
17
|
-
# @example Convert to/from hash
|
|
18
|
-
# hash = snapshot.to_hash
|
|
19
|
-
# snapshot = SwarmSDK::Snapshot.from_hash(hash)
|
|
20
|
-
class Snapshot
|
|
21
|
-
attr_reader :data
|
|
22
|
-
|
|
23
|
-
# Initialize snapshot with data
|
|
24
|
-
#
|
|
25
|
-
# @param data [Hash] Snapshot data hash
|
|
26
|
-
def initialize(data)
|
|
27
|
-
@data = data
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Convert snapshot to hash
|
|
31
|
-
#
|
|
32
|
-
# @return [Hash] Snapshot data as hash
|
|
33
|
-
def to_hash
|
|
34
|
-
@data
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Convert snapshot to JSON string
|
|
38
|
-
#
|
|
39
|
-
# @param pretty [Boolean] Whether to pretty-print JSON (default: true)
|
|
40
|
-
# @return [String] JSON string
|
|
41
|
-
def to_json(pretty: true)
|
|
42
|
-
if pretty
|
|
43
|
-
JSON.pretty_generate(@data)
|
|
44
|
-
else
|
|
45
|
-
JSON.generate(@data)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Write snapshot to file as JSON
|
|
50
|
-
#
|
|
51
|
-
# Uses atomic write pattern (write to temp file, then rename) to prevent
|
|
52
|
-
# corruption if process crashes during write.
|
|
53
|
-
#
|
|
54
|
-
# @param path [String] File path to write to
|
|
55
|
-
# @param pretty [Boolean] Whether to pretty-print JSON (default: true)
|
|
56
|
-
# @return [void]
|
|
57
|
-
def write_to_file(path, pretty: true)
|
|
58
|
-
# Atomic write: write to temp file, then rename
|
|
59
|
-
# This ensures the snapshot file is never corrupted even if process crashes
|
|
60
|
-
temp_path = "#{path}.tmp.#{Process.pid}.#{Time.now.to_i}.#{SecureRandom.hex(4)}"
|
|
61
|
-
|
|
62
|
-
File.write(temp_path, to_json(pretty: pretty))
|
|
63
|
-
File.rename(temp_path, path)
|
|
64
|
-
rescue
|
|
65
|
-
# Clean up temp file if it exists
|
|
66
|
-
File.delete(temp_path) if File.exist?(temp_path)
|
|
67
|
-
raise
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
class << self
|
|
71
|
-
# Create snapshot from hash
|
|
72
|
-
#
|
|
73
|
-
# @param hash [Hash] Snapshot data hash
|
|
74
|
-
# @return [Snapshot] New snapshot instance
|
|
75
|
-
def from_hash(hash)
|
|
76
|
-
new(hash)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Create snapshot from JSON string
|
|
80
|
-
#
|
|
81
|
-
# @param json_string [String] JSON string
|
|
82
|
-
# @return [Snapshot] New snapshot instance
|
|
83
|
-
def from_json(json_string)
|
|
84
|
-
hash = JSON.parse(json_string, symbolize_names: true)
|
|
85
|
-
new(hash)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Create snapshot from JSON file
|
|
89
|
-
#
|
|
90
|
-
# @param path [String] File path to read from
|
|
91
|
-
# @return [Snapshot] New snapshot instance
|
|
92
|
-
def from_file(path)
|
|
93
|
-
json_string = File.read(path)
|
|
94
|
-
from_json(json_string)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Get snapshot version
|
|
99
|
-
#
|
|
100
|
-
# @return [String] Snapshot version
|
|
101
|
-
def version
|
|
102
|
-
@data[:version] || @data["version"]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# Get snapshot type (swarm or workflow)
|
|
106
|
-
#
|
|
107
|
-
# @return [String] Snapshot type
|
|
108
|
-
def type
|
|
109
|
-
@data[:type] || @data["type"]
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Get timestamp when snapshot was created
|
|
113
|
-
#
|
|
114
|
-
# @return [String] ISO8601 timestamp
|
|
115
|
-
def snapshot_at
|
|
116
|
-
@data[:snapshot_at] || @data["snapshot_at"]
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Get SwarmSDK version that created this snapshot
|
|
120
|
-
#
|
|
121
|
-
# @return [String] SwarmSDK version
|
|
122
|
-
def swarm_sdk_version
|
|
123
|
-
@data[:swarm_sdk_version] || @data["swarm_sdk_version"]
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Get agent names from snapshot
|
|
127
|
-
#
|
|
128
|
-
# @return [Array<String>] Agent names
|
|
129
|
-
def agent_names
|
|
130
|
-
agents = @data[:agents] || @data["agents"]
|
|
131
|
-
agents ? agents.keys.map(&:to_s) : []
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Get delegation instance names from snapshot
|
|
135
|
-
#
|
|
136
|
-
# @return [Array<String>] Delegation instance names
|
|
137
|
-
def delegation_instance_names
|
|
138
|
-
delegations = @data[:delegation_instances] || @data["delegation_instances"]
|
|
139
|
-
delegations ? delegations.keys.map(&:to_s) : []
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Check if snapshot is for a swarm (vs workflow)
|
|
143
|
-
#
|
|
144
|
-
# @return [Boolean] true if swarm snapshot
|
|
145
|
-
def swarm?
|
|
146
|
-
type == "swarm"
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Check if snapshot is for a workflow
|
|
150
|
-
#
|
|
151
|
-
# @return [Boolean] true if workflow snapshot
|
|
152
|
-
def workflow?
|
|
153
|
-
type == "workflow"
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|