claude_swarm 1.0.1 → 1.0.2
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/.claude/commands/release.md +1 -1
- data/.claude/hooks/lint-code-files.rb +65 -0
- data/.rubocop.yml +22 -2
- data/CHANGELOG.md +14 -1
- data/CLAUDE.md +1 -1
- data/CONTRIBUTING.md +69 -0
- data/README.md +27 -2
- data/Rakefile +71 -3
- data/analyze_coverage.rb +94 -0
- data/docs/v2/CHANGELOG.swarm_cli.md +43 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +379 -0
- data/docs/v2/CHANGELOG.swarm_sdk.md +362 -0
- data/docs/v2/README.md +308 -0
- data/docs/v2/guides/claude-code-agents.md +262 -0
- data/docs/v2/guides/complete-tutorial.md +3088 -0
- data/docs/v2/guides/getting-started.md +1456 -0
- data/docs/v2/guides/memory-adapters.md +998 -0
- data/docs/v2/guides/plugins.md +816 -0
- data/docs/v2/guides/quick-start-cli.md +1745 -0
- data/docs/v2/guides/rails-integration.md +1902 -0
- data/docs/v2/guides/swarm-memory.md +599 -0
- data/docs/v2/reference/cli.md +729 -0
- data/docs/v2/reference/ruby-dsl.md +2154 -0
- data/docs/v2/reference/yaml.md +1835 -0
- data/docs-team-swarm.yml +2222 -0
- data/examples/learning-assistant/assistant.md +7 -0
- data/examples/learning-assistant/example-memories/concept-example.md +90 -0
- data/examples/learning-assistant/example-memories/experience-example.md +66 -0
- data/examples/learning-assistant/example-memories/fact-example.md +76 -0
- data/examples/learning-assistant/example-memories/memory-index.md +78 -0
- data/examples/learning-assistant/example-memories/skill-example.md +168 -0
- data/examples/learning-assistant/learning_assistant.rb +34 -0
- data/examples/learning-assistant/learning_assistant.yml +20 -0
- data/examples/v2/dsl/01_basic.rb +44 -0
- data/examples/v2/dsl/02_core_parameters.rb +59 -0
- data/examples/v2/dsl/03_capabilities.rb +71 -0
- data/examples/v2/dsl/04_llm_parameters.rb +56 -0
- data/examples/v2/dsl/05_advanced_flags.rb +73 -0
- data/examples/v2/dsl/06_permissions.rb +80 -0
- data/examples/v2/dsl/07_mcp_server.rb +62 -0
- data/examples/v2/dsl/08_swarm_hooks.rb +53 -0
- data/examples/v2/dsl/09_agent_hooks.rb +67 -0
- data/examples/v2/dsl/10_all_agents_hooks.rb +67 -0
- data/examples/v2/dsl/11_delegation.rb +60 -0
- data/examples/v2/dsl/12_complete_integration.rb +137 -0
- data/examples/v2/file_tools_swarm.yml +102 -0
- data/examples/v2/hooks/01_basic_hooks.rb +133 -0
- data/examples/v2/hooks/02_usage_tracking.rb +201 -0
- data/examples/v2/hooks/03_production_monitoring.rb +429 -0
- data/examples/v2/hooks/agent_stop_exit_0.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_1.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_2.yml +26 -0
- data/examples/v2/hooks/multiple_hooks_all_pass.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_first_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_second_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_warnings.yml +37 -0
- data/examples/v2/hooks/post_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_2.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_2.yml +27 -0
- data/examples/v2/hooks/swarm_summary.sh +44 -0
- data/examples/v2/hooks/user_prompt_exit_0.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_1.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_2.yml +21 -0
- data/examples/v2/hooks/validate_bash.rb +59 -0
- data/examples/v2/multi_directory_permissions.yml +221 -0
- data/examples/v2/node_context_demo.rb +127 -0
- data/examples/v2/node_workflow.rb +173 -0
- data/examples/v2/path_resolution_demo.rb +216 -0
- data/examples/v2/simple-swarm-v2.rb +90 -0
- data/examples/v2/simple-swarm-v2.yml +62 -0
- data/examples/v2/swarm.yml +71 -0
- data/examples/v2/swarm_with_hooks.yml +61 -0
- data/examples/v2/swarm_with_hooks_simple.yml +25 -0
- data/examples/v2/think_tool_demo.rb +62 -0
- data/exe/swarm +6 -0
- data/lib/claude_swarm/claude_mcp_server.rb +0 -6
- data/lib/claude_swarm/cli.rb +10 -3
- data/lib/claude_swarm/commands/ps.rb +19 -20
- data/lib/claude_swarm/commands/show.rb +1 -1
- data/lib/claude_swarm/configuration.rb +10 -12
- data/lib/claude_swarm/mcp_generator.rb +10 -1
- data/lib/claude_swarm/orchestrator.rb +73 -49
- data/lib/claude_swarm/system_utils.rb +37 -11
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm/worktree_manager.rb +1 -0
- data/lib/claude_swarm/yaml_loader.rb +22 -0
- data/lib/claude_swarm.rb +6 -2
- data/lib/swarm_cli/cli.rb +201 -0
- data/lib/swarm_cli/command_registry.rb +61 -0
- data/lib/swarm_cli/commands/mcp_serve.rb +130 -0
- data/lib/swarm_cli/commands/mcp_tools.rb +148 -0
- data/lib/swarm_cli/commands/migrate.rb +55 -0
- data/lib/swarm_cli/commands/run.rb +173 -0
- data/lib/swarm_cli/config_loader.rb +97 -0
- data/lib/swarm_cli/formatters/human_formatter.rb +711 -0
- data/lib/swarm_cli/formatters/json_formatter.rb +51 -0
- data/lib/swarm_cli/interactive_repl.rb +918 -0
- data/lib/swarm_cli/mcp_serve_options.rb +44 -0
- data/lib/swarm_cli/mcp_tools_options.rb +59 -0
- data/lib/swarm_cli/migrate_options.rb +54 -0
- data/lib/swarm_cli/migrator.rb +132 -0
- data/lib/swarm_cli/options.rb +151 -0
- data/lib/swarm_cli/ui/components/agent_badge.rb +33 -0
- data/lib/swarm_cli/ui/components/content_block.rb +120 -0
- data/lib/swarm_cli/ui/components/divider.rb +57 -0
- data/lib/swarm_cli/ui/components/panel.rb +62 -0
- data/lib/swarm_cli/ui/components/usage_stats.rb +70 -0
- data/lib/swarm_cli/ui/formatters/cost.rb +49 -0
- data/lib/swarm_cli/ui/formatters/number.rb +58 -0
- data/lib/swarm_cli/ui/formatters/text.rb +77 -0
- data/lib/swarm_cli/ui/formatters/time.rb +73 -0
- data/lib/swarm_cli/ui/icons.rb +59 -0
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +188 -0
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +45 -0
- data/lib/swarm_cli/ui/state/depth_tracker.rb +40 -0
- data/lib/swarm_cli/ui/state/spinner_manager.rb +170 -0
- data/lib/swarm_cli/ui/state/usage_tracker.rb +62 -0
- data/lib/swarm_cli/version.rb +5 -0
- data/lib/swarm_cli.rb +44 -0
- data/lib/swarm_memory/adapters/base.rb +141 -0
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +845 -0
- data/lib/swarm_memory/chat_extension.rb +34 -0
- data/lib/swarm_memory/cli/commands.rb +306 -0
- data/lib/swarm_memory/core/entry.rb +37 -0
- data/lib/swarm_memory/core/frontmatter_parser.rb +108 -0
- data/lib/swarm_memory/core/metadata_extractor.rb +68 -0
- data/lib/swarm_memory/core/path_normalizer.rb +75 -0
- data/lib/swarm_memory/core/semantic_index.rb +244 -0
- data/lib/swarm_memory/core/storage.rb +288 -0
- data/lib/swarm_memory/core/storage_read_tracker.rb +63 -0
- data/lib/swarm_memory/dsl/builder_extension.rb +40 -0
- data/lib/swarm_memory/dsl/memory_config.rb +113 -0
- data/lib/swarm_memory/embeddings/embedder.rb +36 -0
- data/lib/swarm_memory/embeddings/informers_embedder.rb +152 -0
- data/lib/swarm_memory/errors.rb +21 -0
- data/lib/swarm_memory/integration/cli_registration.rb +30 -0
- data/lib/swarm_memory/integration/configuration.rb +43 -0
- data/lib/swarm_memory/integration/registration.rb +31 -0
- data/lib/swarm_memory/integration/sdk_plugin.rb +531 -0
- data/lib/swarm_memory/optimization/analyzer.rb +244 -0
- data/lib/swarm_memory/optimization/defragmenter.rb +863 -0
- data/lib/swarm_memory/prompts/memory.md.erb +109 -0
- data/lib/swarm_memory/prompts/memory_assistant.md.erb +181 -0
- data/lib/swarm_memory/prompts/memory_researcher.md.erb +281 -0
- data/lib/swarm_memory/prompts/memory_retrieval.md.erb +78 -0
- data/lib/swarm_memory/search/semantic_search.rb +112 -0
- data/lib/swarm_memory/search/text_search.rb +42 -0
- data/lib/swarm_memory/search/text_similarity.rb +80 -0
- data/lib/swarm_memory/skills/meta/deep-learning.md +101 -0
- data/lib/swarm_memory/skills/meta/deep-learning.yml +14 -0
- data/lib/swarm_memory/tools/load_skill.rb +313 -0
- data/lib/swarm_memory/tools/memory_defrag.rb +382 -0
- data/lib/swarm_memory/tools/memory_delete.rb +99 -0
- data/lib/swarm_memory/tools/memory_edit.rb +185 -0
- data/lib/swarm_memory/tools/memory_glob.rb +160 -0
- data/lib/swarm_memory/tools/memory_grep.rb +247 -0
- data/lib/swarm_memory/tools/memory_multi_edit.rb +281 -0
- data/lib/swarm_memory/tools/memory_read.rb +123 -0
- data/lib/swarm_memory/tools/memory_write.rb +231 -0
- data/lib/swarm_memory/utils.rb +50 -0
- data/lib/swarm_memory/version.rb +5 -0
- data/lib/swarm_memory.rb +166 -0
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +127 -0
- data/lib/swarm_sdk/agent/builder.rb +461 -0
- data/lib/swarm_sdk/agent/chat/context_tracker.rb +314 -0
- data/lib/swarm_sdk/agent/chat/hook_integration.rb +372 -0
- data/lib/swarm_sdk/agent/chat/logging_helpers.rb +116 -0
- data/lib/swarm_sdk/agent/chat/system_reminder_injector.rb +152 -0
- data/lib/swarm_sdk/agent/chat.rb +1159 -0
- data/lib/swarm_sdk/agent/context.rb +112 -0
- data/lib/swarm_sdk/agent/context_manager.rb +309 -0
- data/lib/swarm_sdk/agent/definition.rb +556 -0
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +205 -0
- data/lib/swarm_sdk/configuration.rb +296 -0
- data/lib/swarm_sdk/context_compactor/metrics.rb +147 -0
- data/lib/swarm_sdk/context_compactor/token_counter.rb +106 -0
- data/lib/swarm_sdk/context_compactor.rb +340 -0
- data/lib/swarm_sdk/hooks/adapter.rb +359 -0
- data/lib/swarm_sdk/hooks/context.rb +197 -0
- data/lib/swarm_sdk/hooks/definition.rb +80 -0
- data/lib/swarm_sdk/hooks/error.rb +29 -0
- data/lib/swarm_sdk/hooks/executor.rb +146 -0
- data/lib/swarm_sdk/hooks/registry.rb +147 -0
- data/lib/swarm_sdk/hooks/result.rb +150 -0
- data/lib/swarm_sdk/hooks/shell_executor.rb +254 -0
- data/lib/swarm_sdk/hooks/tool_call.rb +35 -0
- data/lib/swarm_sdk/hooks/tool_result.rb +62 -0
- data/lib/swarm_sdk/log_collector.rb +51 -0
- data/lib/swarm_sdk/log_stream.rb +69 -0
- data/lib/swarm_sdk/markdown_parser.rb +75 -0
- data/lib/swarm_sdk/model_aliases.json +5 -0
- data/lib/swarm_sdk/models.json +1 -0
- data/lib/swarm_sdk/models.rb +120 -0
- data/lib/swarm_sdk/node/agent_config.rb +49 -0
- data/lib/swarm_sdk/node/builder.rb +439 -0
- data/lib/swarm_sdk/node/transformer_executor.rb +248 -0
- data/lib/swarm_sdk/node_context.rb +170 -0
- data/lib/swarm_sdk/node_orchestrator.rb +384 -0
- data/lib/swarm_sdk/permissions/config.rb +239 -0
- data/lib/swarm_sdk/permissions/error_formatter.rb +121 -0
- data/lib/swarm_sdk/permissions/path_matcher.rb +35 -0
- data/lib/swarm_sdk/permissions/validator.rb +173 -0
- data/lib/swarm_sdk/permissions_builder.rb +122 -0
- data/lib/swarm_sdk/plugin.rb +147 -0
- data/lib/swarm_sdk/plugin_registry.rb +101 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +243 -0
- data/lib/swarm_sdk/providers/openai_with_responses.rb +582 -0
- data/lib/swarm_sdk/result.rb +97 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +334 -0
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +140 -0
- data/lib/swarm_sdk/swarm/builder.rb +586 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +151 -0
- data/lib/swarm_sdk/swarm/tool_configurator.rb +419 -0
- data/lib/swarm_sdk/swarm.rb +982 -0
- data/lib/swarm_sdk/tools/bash.rb +274 -0
- data/lib/swarm_sdk/tools/clock.rb +44 -0
- data/lib/swarm_sdk/tools/delegate.rb +164 -0
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +83 -0
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +99 -0
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +101 -0
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +78 -0
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +194 -0
- data/lib/swarm_sdk/tools/edit.rb +150 -0
- data/lib/swarm_sdk/tools/glob.rb +158 -0
- data/lib/swarm_sdk/tools/grep.rb +228 -0
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +43 -0
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +163 -0
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +65 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +232 -0
- data/lib/swarm_sdk/tools/path_resolver.rb +43 -0
- data/lib/swarm_sdk/tools/read.rb +251 -0
- data/lib/swarm_sdk/tools/registry.rb +93 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +96 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +76 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +91 -0
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +61 -0
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +224 -0
- data/lib/swarm_sdk/tools/stores/storage.rb +148 -0
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +65 -0
- data/lib/swarm_sdk/tools/think.rb +95 -0
- data/lib/swarm_sdk/tools/todo_write.rb +216 -0
- data/lib/swarm_sdk/tools/web_fetch.rb +261 -0
- data/lib/swarm_sdk/tools/write.rb +117 -0
- data/lib/swarm_sdk/utils.rb +50 -0
- data/lib/swarm_sdk/version.rb +5 -0
- data/lib/swarm_sdk.rb +157 -0
- data/llm.v2.txt +13407 -0
- data/rubocop/cop/security/no_reflection_methods.rb +47 -0
- data/rubocop/cop/security/no_ruby_llm_logger.rb +32 -0
- data/swarm_cli.gemspec +57 -0
- data/swarm_memory.gemspec +28 -0
- data/swarm_sdk.gemspec +41 -0
- data/team.yml +1 -1
- data/team_full.yml +1875 -0
- data/{team_v2.yml → team_sdk.yml} +121 -52
- metadata +247 -4
- data/EXAMPLES.md +0 -164
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module DSL
|
|
5
|
+
# Memory configuration for agents
|
|
6
|
+
#
|
|
7
|
+
# This class is injected into SwarmSDK when swarm_memory is required,
|
|
8
|
+
# allowing agents to configure memory via the DSL.
|
|
9
|
+
#
|
|
10
|
+
# Supports custom adapters through options hash that gets passed through
|
|
11
|
+
# to the adapter constructor.
|
|
12
|
+
#
|
|
13
|
+
# @example Filesystem adapter
|
|
14
|
+
# memory do
|
|
15
|
+
# adapter :filesystem
|
|
16
|
+
# directory ".swarm/memory"
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @example Custom adapter
|
|
20
|
+
# memory do
|
|
21
|
+
# adapter :activerecord
|
|
22
|
+
# option :namespace, "my_agent"
|
|
23
|
+
# option :table_name, "memory_entries"
|
|
24
|
+
# end
|
|
25
|
+
class MemoryConfig
|
|
26
|
+
attr_reader :adapter_type, :adapter_options
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
@adapter_type = :filesystem # Default adapter
|
|
30
|
+
@adapter_options = {} # Options passed to adapter constructor
|
|
31
|
+
@mode = :assistant # Default mode
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# DSL method to set/get adapter type
|
|
35
|
+
#
|
|
36
|
+
# @param value [Symbol, nil] Adapter type
|
|
37
|
+
# @return [Symbol] Current adapter
|
|
38
|
+
def adapter(value = nil)
|
|
39
|
+
return @adapter_type if value.nil?
|
|
40
|
+
|
|
41
|
+
@adapter_type = value.to_sym
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# DSL method to set adapter option (generic)
|
|
45
|
+
#
|
|
46
|
+
# This allows passing any option to the adapter constructor.
|
|
47
|
+
#
|
|
48
|
+
# @param key [Symbol] Option key
|
|
49
|
+
# @param value [Object] Option value
|
|
50
|
+
#
|
|
51
|
+
# @example
|
|
52
|
+
# option :namespace, "my_agent"
|
|
53
|
+
# option :connection_pool_size, 5
|
|
54
|
+
def option(key, value)
|
|
55
|
+
@adapter_options[key.to_sym] = value
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# DSL method to set/get directory (convenience for filesystem adapter)
|
|
59
|
+
#
|
|
60
|
+
# Equivalent to: option :directory, value
|
|
61
|
+
#
|
|
62
|
+
# @param value [String, nil] Memory directory path
|
|
63
|
+
# @return [String] Current directory
|
|
64
|
+
def directory(value = nil)
|
|
65
|
+
if value.nil?
|
|
66
|
+
@adapter_options[:directory]
|
|
67
|
+
else
|
|
68
|
+
@adapter_options[:directory] = value
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# DSL method to set/get mode
|
|
73
|
+
#
|
|
74
|
+
# Modes:
|
|
75
|
+
# - :assistant (default) - Read + Write, balanced for learning and retrieval
|
|
76
|
+
# - :retrieval - Read-only, optimized for Q&A
|
|
77
|
+
# - :researcher - All tools, optimized for knowledge extraction
|
|
78
|
+
#
|
|
79
|
+
# @param value [Symbol, nil] Memory mode
|
|
80
|
+
# @return [Symbol] Current mode
|
|
81
|
+
def mode(value = nil)
|
|
82
|
+
return @mode if value.nil?
|
|
83
|
+
|
|
84
|
+
@mode = value.to_sym
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Check if memory is enabled
|
|
88
|
+
#
|
|
89
|
+
# @return [Boolean] True if adapter is configured with required options
|
|
90
|
+
def enabled?
|
|
91
|
+
case @adapter_type
|
|
92
|
+
when :filesystem
|
|
93
|
+
!@adapter_options[:directory].nil?
|
|
94
|
+
else
|
|
95
|
+
# For custom adapters, assume enabled if adapter is set
|
|
96
|
+
# Custom adapter will validate its own requirements
|
|
97
|
+
true
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Convert config to hash (for SDK plugin)
|
|
102
|
+
#
|
|
103
|
+
# @return [Hash] Configuration as hash
|
|
104
|
+
def to_h
|
|
105
|
+
{
|
|
106
|
+
adapter: @adapter_type,
|
|
107
|
+
mode: @mode,
|
|
108
|
+
**@adapter_options,
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module Embeddings
|
|
5
|
+
# Abstract embedder interface
|
|
6
|
+
#
|
|
7
|
+
# Subclasses implement different embedding providers
|
|
8
|
+
# (Informers, OpenAI API, etc.)
|
|
9
|
+
class Embedder
|
|
10
|
+
# Generate embedding for single text
|
|
11
|
+
#
|
|
12
|
+
# @param text [String] Text to embed
|
|
13
|
+
# @return [Array<Float>] Embedding vector
|
|
14
|
+
# @raise [EmbeddingError] If embedding generation fails
|
|
15
|
+
def embed(text)
|
|
16
|
+
raise NotImplementedError, "Subclass must implement #embed"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Generate embeddings for multiple texts (batched)
|
|
20
|
+
#
|
|
21
|
+
# @param texts [Array<String>] Texts to embed
|
|
22
|
+
# @return [Array<Array<Float>>] Array of embedding vectors
|
|
23
|
+
# @raise [EmbeddingError] If embedding generation fails
|
|
24
|
+
def embed_batch(texts)
|
|
25
|
+
raise NotImplementedError, "Subclass must implement #embed_batch"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get embedding dimensionality
|
|
29
|
+
#
|
|
30
|
+
# @return [Integer] Vector dimensions
|
|
31
|
+
def dimensions
|
|
32
|
+
raise NotImplementedError, "Subclass must implement #dimensions"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module Embeddings
|
|
5
|
+
# Embedder implementation using Informers gem (fast ONNX inference)
|
|
6
|
+
#
|
|
7
|
+
# Uses sentence-transformers models via ONNX for fast, local embedding generation.
|
|
8
|
+
# Supports quantized models for even better performance.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# embedder = InformersEmbedder.new
|
|
12
|
+
# vector = embedder.embed("This is a test sentence")
|
|
13
|
+
# vector.size # => 384
|
|
14
|
+
class InformersEmbedder < Embedder
|
|
15
|
+
DEFAULT_MODEL = "sentence-transformers/multi-qa-MiniLM-L6-cos-v1"
|
|
16
|
+
EMBEDDING_DIMENSIONS = 384
|
|
17
|
+
|
|
18
|
+
# Initialize embedder with model configuration
|
|
19
|
+
#
|
|
20
|
+
# Model can be configured via SWARM_MEMORY_EMBEDDING_MODEL environment variable.
|
|
21
|
+
#
|
|
22
|
+
# Available models:
|
|
23
|
+
# - sentence-transformers/all-MiniLM-L6-v2 (default, general purpose, 256 tokens)
|
|
24
|
+
# - sentence-transformers/multi-qa-MiniLM-L6-cos-v1 (Q&A optimized, 512 tokens)
|
|
25
|
+
#
|
|
26
|
+
# @param model [String, nil] HuggingFace model identifier (defaults to env var or DEFAULT_MODEL)
|
|
27
|
+
# @param quantized [Boolean] Use quantized variant (default: false for original model)
|
|
28
|
+
# @param cache_dir [String, nil] Optional custom cache directory
|
|
29
|
+
# @raise [EmbeddingError] If Informers gem is not available
|
|
30
|
+
#
|
|
31
|
+
# Note: The original sentence-transformers model uses unquantized ONNX (90MB).
|
|
32
|
+
# For a smaller quantized version (22MB), use model: "Xenova/all-MiniLM-L6-v2", quantized: true
|
|
33
|
+
def initialize(model: nil, quantized: false, cache_dir: nil)
|
|
34
|
+
super()
|
|
35
|
+
|
|
36
|
+
unless defined?(Informers)
|
|
37
|
+
raise EmbeddingError,
|
|
38
|
+
"Informers gem is not available. Install with: gem install informers"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Use env var if available, otherwise use provided model or default
|
|
42
|
+
@model_name = model || ENV["SWARM_MEMORY_EMBEDDING_MODEL"] || DEFAULT_MODEL
|
|
43
|
+
@quantized = quantized
|
|
44
|
+
@model = nil # Lazy load
|
|
45
|
+
|
|
46
|
+
# Optional: Set custom cache directory
|
|
47
|
+
Informers.cache_dir = cache_dir if cache_dir
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Explicitly pre-load the model (triggers download if not cached)
|
|
51
|
+
#
|
|
52
|
+
# Call this during initialization to download the model immediately
|
|
53
|
+
# rather than waiting for the first embedding call.
|
|
54
|
+
#
|
|
55
|
+
# @return [self]
|
|
56
|
+
#
|
|
57
|
+
# @example
|
|
58
|
+
# embedder = InformersEmbedder.new
|
|
59
|
+
# embedder.preload! # Downloads ~80MB model on first call
|
|
60
|
+
# embedder.embed("text") # No download wait
|
|
61
|
+
def preload!
|
|
62
|
+
ensure_model_loaded
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Check if model is already cached locally
|
|
67
|
+
#
|
|
68
|
+
# @return [Boolean] True if model files exist in cache
|
|
69
|
+
#
|
|
70
|
+
# @example
|
|
71
|
+
# embedder = InformersEmbedder.new
|
|
72
|
+
# if embedder.cached?
|
|
73
|
+
# puts "Ready to use!"
|
|
74
|
+
# else
|
|
75
|
+
# puts "Will download on first use (~80MB)"
|
|
76
|
+
# end
|
|
77
|
+
def cached?
|
|
78
|
+
cache_dir = Informers.cache_dir
|
|
79
|
+
|
|
80
|
+
# Different models have different file names
|
|
81
|
+
# Original sentence-transformers: model.onnx (unquantized)
|
|
82
|
+
# Xenova version: model_quantized.onnx (quantized)
|
|
83
|
+
suffix = @quantized ? "_quantized" : ""
|
|
84
|
+
|
|
85
|
+
# Check for required model files
|
|
86
|
+
model_file = File.join(cache_dir, @model_name, "onnx", "model#{suffix}.onnx")
|
|
87
|
+
tokenizer_file = File.join(cache_dir, @model_name, "tokenizer.json")
|
|
88
|
+
|
|
89
|
+
File.exist?(model_file) && File.exist?(tokenizer_file)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Generate embedding for single text
|
|
93
|
+
#
|
|
94
|
+
# @param text [String] Text to embed
|
|
95
|
+
# @return [Array<Float>] 384-dimensional embedding vector
|
|
96
|
+
# @raise [EmbeddingError] If embedding generation fails
|
|
97
|
+
def embed(text)
|
|
98
|
+
raise ArgumentError, "text is required" if text.nil? || text.to_s.strip.empty?
|
|
99
|
+
|
|
100
|
+
begin
|
|
101
|
+
ensure_model_loaded
|
|
102
|
+
# Informers handles single strings directly - returns single embedding array
|
|
103
|
+
@model.call(text)
|
|
104
|
+
rescue StandardError => e
|
|
105
|
+
raise EmbeddingError, "Failed to generate embedding: #{e.message}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Generate embeddings for multiple texts (batched)
|
|
110
|
+
#
|
|
111
|
+
# @param texts [Array<String>] Texts to embed
|
|
112
|
+
# @return [Array<Array<Float>>] Array of embedding vectors
|
|
113
|
+
# @raise [EmbeddingError] If embedding generation fails
|
|
114
|
+
def embed_batch(texts)
|
|
115
|
+
raise ArgumentError, "texts must be an array" unless texts.is_a?(Array)
|
|
116
|
+
raise ArgumentError, "texts cannot be empty" if texts.empty?
|
|
117
|
+
|
|
118
|
+
begin
|
|
119
|
+
ensure_model_loaded
|
|
120
|
+
# Batch call - returns array of embedding arrays
|
|
121
|
+
@model.call(texts)
|
|
122
|
+
rescue StandardError => e
|
|
123
|
+
raise EmbeddingError, "Failed to generate embeddings: #{e.message}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Get embedding dimensionality
|
|
128
|
+
#
|
|
129
|
+
# @return [Integer] Vector dimensions (384 for all-MiniLM-L6-v2)
|
|
130
|
+
def dimensions
|
|
131
|
+
EMBEDDING_DIMENSIONS
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
# Lazy load the Informers model
|
|
137
|
+
#
|
|
138
|
+
# @return [void]
|
|
139
|
+
def ensure_model_loaded
|
|
140
|
+
return if @model
|
|
141
|
+
|
|
142
|
+
@model = Informers.pipeline(
|
|
143
|
+
"embedding",
|
|
144
|
+
@model_name,
|
|
145
|
+
quantized: @quantized,
|
|
146
|
+
)
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
raise EmbeddingError, "Failed to load embedding model '#{@model_name}': #{e.message}"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
# Base error class for SwarmMemory
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Configuration errors
|
|
8
|
+
class ConfigurationError < Error; end
|
|
9
|
+
|
|
10
|
+
# Storage operation errors
|
|
11
|
+
class StorageError < Error; end
|
|
12
|
+
|
|
13
|
+
# Adapter-specific errors
|
|
14
|
+
class AdapterError < Error; end
|
|
15
|
+
|
|
16
|
+
# Search operation errors
|
|
17
|
+
class SearchError < Error; end
|
|
18
|
+
|
|
19
|
+
# Embedding generation errors
|
|
20
|
+
class EmbeddingError < Error; end
|
|
21
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module Integration
|
|
5
|
+
# Auto-registration for SwarmCLI commands
|
|
6
|
+
#
|
|
7
|
+
# Registers memory management commands with SwarmCLI when available.
|
|
8
|
+
class CliRegistration
|
|
9
|
+
class << self
|
|
10
|
+
# Register memory CLI commands with SwarmCLI
|
|
11
|
+
#
|
|
12
|
+
# This is called automatically when swarm_memory is required.
|
|
13
|
+
#
|
|
14
|
+
# @return [void]
|
|
15
|
+
def register!
|
|
16
|
+
# Only register if SwarmCLI is present
|
|
17
|
+
return unless defined?(SwarmCLI)
|
|
18
|
+
|
|
19
|
+
# Load CLI commands explicitly (Zeitwerk might not have loaded it yet)
|
|
20
|
+
require_relative "../cli/commands"
|
|
21
|
+
|
|
22
|
+
# Register memory command
|
|
23
|
+
SwarmCLI::CommandRegistry.register(:memory, SwarmMemory::CLI::Commands)
|
|
24
|
+
rescue StandardError => e
|
|
25
|
+
warn("Warning: Failed to register SwarmMemory CLI commands: #{e.message}")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module Integration
|
|
5
|
+
# Configuration for agent memory
|
|
6
|
+
#
|
|
7
|
+
# Used by SwarmSDK to configure memory settings for agents.
|
|
8
|
+
# This mirrors the MemoryConfig in SwarmSDK but lives in SwarmMemory.
|
|
9
|
+
class Configuration
|
|
10
|
+
def initialize
|
|
11
|
+
@adapter = :filesystem
|
|
12
|
+
@directory = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# DSL method to set/get adapter
|
|
16
|
+
#
|
|
17
|
+
# @param value [Symbol, String, nil] Adapter type (:filesystem, :redis, etc.)
|
|
18
|
+
# @return [Symbol] Current adapter
|
|
19
|
+
def adapter(value = nil)
|
|
20
|
+
return @adapter if value.nil?
|
|
21
|
+
|
|
22
|
+
@adapter = value.to_sym
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# DSL method to set/get directory
|
|
26
|
+
#
|
|
27
|
+
# @param value [String, nil] Directory path for storage
|
|
28
|
+
# @return [String, nil] Current directory
|
|
29
|
+
def directory(value = nil)
|
|
30
|
+
return @directory if value.nil?
|
|
31
|
+
|
|
32
|
+
@directory = value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check if memory is enabled
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean] True if directory is set
|
|
38
|
+
def enabled?
|
|
39
|
+
!@directory.nil?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmMemory
|
|
4
|
+
module Integration
|
|
5
|
+
# Auto-registration with SwarmSDK
|
|
6
|
+
#
|
|
7
|
+
# Registers SwarmMemory plugin with SwarmSDK when the swarm_memory gem is loaded.
|
|
8
|
+
# This enables SwarmSDK to automatically use SwarmMemory features.
|
|
9
|
+
class Registration
|
|
10
|
+
class << self
|
|
11
|
+
# Register SwarmMemory plugin with SwarmSDK
|
|
12
|
+
#
|
|
13
|
+
# This is called automatically when swarm_memory is required.
|
|
14
|
+
# It registers the plugin so SwarmSDK can provide memory tools and storage.
|
|
15
|
+
#
|
|
16
|
+
# @return [void]
|
|
17
|
+
def register!
|
|
18
|
+
# Only register if SwarmSDK is present
|
|
19
|
+
return unless defined?(SwarmSDK)
|
|
20
|
+
return unless defined?(SwarmSDK::PluginRegistry)
|
|
21
|
+
|
|
22
|
+
# Register plugin with SwarmSDK
|
|
23
|
+
plugin = SDKPlugin.new
|
|
24
|
+
SwarmSDK::PluginRegistry.register(plugin)
|
|
25
|
+
rescue StandardError => e
|
|
26
|
+
warn("Warning: Failed to register SwarmMemory plugin with SwarmSDK: #{e.message}")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|