robot_lab-document_store 0.2.1 → 0.2.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/.envrc +2 -0
- data/.loki +10 -0
- data/.quality/reek_baseline.txt +1 -0
- data/.rubocop.yml +1 -173
- data/CHANGELOG.md +10 -0
- data/CLAUDE.md +72 -0
- data/Rakefile +47 -31
- data/docs/getting_started.md +1 -1
- data/docs/how_it_works.md +1 -1
- data/lib/robot_lab/document_store/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c76daa301371b72ad1a128cc287b84a4b86962851d581807a3b4a86eea758d7a
|
|
4
|
+
data.tar.gz: 3dd0e51ac30391feb45ea59cede650a1d137b9fc54d02cbf63479a484036c6aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb965431ab53192605471ec0b06f9664fc57bea6a97e53bd0956b074e53e95f34a4c689624a171bb655847cbb8d45b9417f6112daa2e89de23618cb2978f94fd
|
|
7
|
+
data.tar.gz: ee8900ebb335b40ffc7adc00db2562919a3d7fbb5eec492cda848b041a458154ca513ac1a8f0a3c8c9a665836d7739faa67e102710576d89d49c8f502115a3a0
|
data/.envrc
CHANGED
data/.loki
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# robot_lab-document_store — vector embeddings & semantic search.
|
|
3
|
+
|
|
4
|
+
import_up "repo_dev.loki"
|
|
5
|
+
|
|
6
|
+
class Tasks
|
|
7
|
+
@@gem_name ||= "robot_lab-document_store".freeze
|
|
8
|
+
|
|
9
|
+
header "robot_lab-document_store v#{gem_version} — vector embeddings & semantic search"
|
|
10
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
9 lib/robot_lab/document_store.rb
|
data/.rubocop.yml
CHANGED
|
@@ -1,173 +1 @@
|
|
|
1
|
-
|
|
2
|
-
NewCops: enable
|
|
3
|
-
SuggestExtensions: false
|
|
4
|
-
TargetRubyVersion: 4.0
|
|
5
|
-
Exclude:
|
|
6
|
-
- 'examples/**/*'
|
|
7
|
-
- 'vendor/**/*'
|
|
8
|
-
- 'dead_code/**/*'
|
|
9
|
-
|
|
10
|
-
# ── Style: disabled cops ───────────────────────────────────────────────────
|
|
11
|
-
Style/StringLiterals:
|
|
12
|
-
Enabled: false
|
|
13
|
-
|
|
14
|
-
Style/StringLiteralsInInterpolation:
|
|
15
|
-
Enabled: false
|
|
16
|
-
|
|
17
|
-
Style/Documentation:
|
|
18
|
-
Enabled: false
|
|
19
|
-
|
|
20
|
-
# Ruby 4.0 freezes string literals by default
|
|
21
|
-
Style/FrozenStringLiteralComment:
|
|
22
|
-
Enabled: false
|
|
23
|
-
|
|
24
|
-
Style/IfUnlessModifier:
|
|
25
|
-
Enabled: false
|
|
26
|
-
|
|
27
|
-
Style/RescueModifier:
|
|
28
|
-
Enabled: false
|
|
29
|
-
|
|
30
|
-
Style/TrivialAccessors:
|
|
31
|
-
Enabled: false
|
|
32
|
-
|
|
33
|
-
Style/MultilineTernaryOperator:
|
|
34
|
-
Enabled: false
|
|
35
|
-
|
|
36
|
-
Style/SafeNavigation:
|
|
37
|
-
Enabled: false
|
|
38
|
-
|
|
39
|
-
Style/EmptyClassDefinition:
|
|
40
|
-
Enabled: false
|
|
41
|
-
|
|
42
|
-
Style/ClassAndModuleChildren:
|
|
43
|
-
Enabled: false
|
|
44
|
-
|
|
45
|
-
Style/RescueStandardError:
|
|
46
|
-
Enabled: false
|
|
47
|
-
|
|
48
|
-
Style/OneClassPerFile:
|
|
49
|
-
Enabled: false
|
|
50
|
-
|
|
51
|
-
# Both % and format/sprintf are acceptable
|
|
52
|
-
Style/FormatString:
|
|
53
|
-
Enabled: false
|
|
54
|
-
|
|
55
|
-
# String concatenation and interpolation are both acceptable
|
|
56
|
-
Style/StringConcatenation:
|
|
57
|
-
Enabled: false
|
|
58
|
-
|
|
59
|
-
# ── Layout ─────────────────────────────────────────────────────────────────
|
|
60
|
-
Layout/LineLength:
|
|
61
|
-
Max: 140
|
|
62
|
-
|
|
63
|
-
Layout/ExtraSpacing:
|
|
64
|
-
Enabled: false
|
|
65
|
-
|
|
66
|
-
Layout/HashAlignment:
|
|
67
|
-
Enabled: false
|
|
68
|
-
|
|
69
|
-
Layout/FirstHashElementIndentation:
|
|
70
|
-
Enabled: false
|
|
71
|
-
|
|
72
|
-
Layout/EmptyLineAfterGuardClause:
|
|
73
|
-
Enabled: false
|
|
74
|
-
|
|
75
|
-
# ── Naming ─────────────────────────────────────────────────────────────────
|
|
76
|
-
# Single-char params (c, e, n) are acceptable throughout
|
|
77
|
-
Naming/MethodParameterName:
|
|
78
|
-
Enabled: false
|
|
79
|
-
|
|
80
|
-
Naming/VariableNumber:
|
|
81
|
-
Exclude:
|
|
82
|
-
- 'test/**/*'
|
|
83
|
-
|
|
84
|
-
Naming/RescuedExceptionsVariableName:
|
|
85
|
-
Enabled: false
|
|
86
|
-
|
|
87
|
-
# set_results and similar explicit setters are clear and conventional
|
|
88
|
-
Naming/AccessorMethodName:
|
|
89
|
-
Enabled: false
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# has_tool_calls? and similar are clear and conventional
|
|
93
|
-
Naming/PredicatePrefix:
|
|
94
|
-
Enabled: false
|
|
95
|
-
|
|
96
|
-
# Test helper methods don't need to follow predicate naming rules
|
|
97
|
-
Naming/PredicateMethod:
|
|
98
|
-
Exclude:
|
|
99
|
-
- 'test/**/*'
|
|
100
|
-
|
|
101
|
-
# ── Lint: relax noisy cops on intentional patterns ─────────────────────────
|
|
102
|
-
# Library and framework methods commonly accept args for API/documentation purposes
|
|
103
|
-
Lint/UnusedMethodArgument:
|
|
104
|
-
Enabled: false
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
Lint/EmptyBlock:
|
|
108
|
-
Exclude:
|
|
109
|
-
- 'test/**/*'
|
|
110
|
-
|
|
111
|
-
Lint/ConstantDefinitionInBlock:
|
|
112
|
-
Exclude:
|
|
113
|
-
- 'Rakefile'
|
|
114
|
-
- 'test/**/*'
|
|
115
|
-
|
|
116
|
-
# ── Gemspec ────────────────────────────────────────────────────────────────
|
|
117
|
-
Gemspec/DevelopmentDependencies:
|
|
118
|
-
EnforcedStyle: Gemfile
|
|
119
|
-
|
|
120
|
-
Gemspec/RequiredRubyVersion:
|
|
121
|
-
Enabled: false
|
|
122
|
-
|
|
123
|
-
Gemspec/OrderedDependencies:
|
|
124
|
-
Enabled: false
|
|
125
|
-
|
|
126
|
-
# ── Metrics ────────────────────────────────────────────────────────────────
|
|
127
|
-
# Framework-level code (routers, parsers, orchestrators) is inherently complex.
|
|
128
|
-
# Flog is the primary complexity gate — these RuboCop thresholds catch only
|
|
129
|
-
# egregious outliers without false-positiving every dispatch method.
|
|
130
|
-
|
|
131
|
-
Metrics/MethodLength:
|
|
132
|
-
Max: 35
|
|
133
|
-
CountAsOne:
|
|
134
|
-
- heredoc
|
|
135
|
-
- array
|
|
136
|
-
- hash
|
|
137
|
-
Exclude:
|
|
138
|
-
- 'test/**/*'
|
|
139
|
-
|
|
140
|
-
Metrics/AbcSize:
|
|
141
|
-
Max: 40
|
|
142
|
-
Exclude:
|
|
143
|
-
- 'test/**/*'
|
|
144
|
-
|
|
145
|
-
Metrics/ClassLength:
|
|
146
|
-
Max: 600
|
|
147
|
-
Exclude:
|
|
148
|
-
- 'test/**/*'
|
|
149
|
-
|
|
150
|
-
Metrics/ModuleLength:
|
|
151
|
-
Max: 200
|
|
152
|
-
Exclude:
|
|
153
|
-
- 'test/**/*'
|
|
154
|
-
|
|
155
|
-
Metrics/CyclomaticComplexity:
|
|
156
|
-
Max: 20
|
|
157
|
-
Exclude:
|
|
158
|
-
- 'test/**/*'
|
|
159
|
-
|
|
160
|
-
Metrics/PerceivedComplexity:
|
|
161
|
-
Max: 20
|
|
162
|
-
Exclude:
|
|
163
|
-
- 'test/**/*'
|
|
164
|
-
|
|
165
|
-
# Long method signatures with keyword args are a Ruby framework idiom
|
|
166
|
-
Metrics/ParameterLists:
|
|
167
|
-
Enabled: false
|
|
168
|
-
|
|
169
|
-
Metrics/BlockLength:
|
|
170
|
-
Exclude:
|
|
171
|
-
- 'Rakefile'
|
|
172
|
-
- '*.gemspec'
|
|
173
|
-
- 'test/**/*'
|
|
1
|
+
inherit_from: ../.rubocop-base.yml
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
### Added
|
|
4
|
+
- `.loki` Asgard task file: `test`, `rubocop`, `rubocop_fix`, `flog`, `flay`, `quality`, `build`, `install`, `release`, and `console` tasks via the Asgard task runner
|
|
5
|
+
- `flay_check` Rake task: structural code duplication gate (mass threshold 50); integrated into the `quality` Rake task
|
|
6
|
+
- `flay` and `minitest-reporters` gems added to development dependencies
|
|
7
|
+
- `test_output.txt`, `flay_output.txt`, `flog_output.txt`, and `rubocop_output.txt` added to `.gitignore`
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `test/test_helper.rb`: test output redirected to `test_output.txt` via `$stdout` reassignment; `TerminalSummaryReporter` prints a single PASS/FAIL summary line to the terminal
|
|
11
|
+
- `Rakefile`: `rubocop` and `rubocop_fix` tasks removed (now owned by Asgard); `flay_check` integrated into the `quality` gate
|
|
12
|
+
|
|
3
13
|
## [0.2.1] - 2026-05-19
|
|
4
14
|
|
|
5
15
|
### Added
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What This Gem Does
|
|
6
|
+
|
|
7
|
+
`robot_lab-document_store` provides a thread-safe, in-memory semantic document store for RobotLab. Documents are embedded and retrieved by cosine similarity. It uses `fastembed` (BAAI/bge-small-en-v1.5) when available, and falls back to a lightweight TF-IDF word-frequency embedder when fastembed is not installed.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle exec rake test # Run full test suite
|
|
13
|
+
ruby -Ilib:test test/<file> # Run a single test file
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
The gem is a single class: `RobotLab::DocumentStore` (`lib/robot_lab/document_store.rb`).
|
|
19
|
+
|
|
20
|
+
### Key Methods
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
store = RobotLab::DocumentStore.new # fastembed model chosen automatically
|
|
24
|
+
store = RobotLab::DocumentStore.new(model_name: "...") # override fastembed model
|
|
25
|
+
|
|
26
|
+
store.store(:key, "text") # embed and store; replaces existing key
|
|
27
|
+
store.search("query", limit: 5) # returns Array<{key:, text:, score:}>
|
|
28
|
+
store.size # Integer
|
|
29
|
+
store.keys # Array<Symbol>
|
|
30
|
+
store.empty? # Boolean
|
|
31
|
+
store.delete(:key) # remove one document
|
|
32
|
+
store.clear # remove all documents
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Search results are sorted by score descending (0.0–1.0). The fastembed model is initialised lazily on the first `store` or `search` call — the ONNX model file is downloaded then cached locally.
|
|
36
|
+
|
|
37
|
+
### Embedding Paths
|
|
38
|
+
|
|
39
|
+
**Fastembed path** (when `fastembed` gem is installed):
|
|
40
|
+
- `passage_embed` for stored documents, `query_embed` for search queries — asymmetric embedding per the BGE model's design
|
|
41
|
+
- Dense float vectors, cosine similarity computed inline
|
|
42
|
+
|
|
43
|
+
**Fallback TF-IDF path** (when fastembed is absent):
|
|
44
|
+
- Stop-word filtered, Porter-style stemmed word frequency vectors
|
|
45
|
+
- Sparse `Hash{String => Float}` L2-normalised vectors
|
|
46
|
+
- `sparse_cosine` for similarity — no semantic understanding, lexical overlap only
|
|
47
|
+
- Good for development and testing without downloading ONNX models
|
|
48
|
+
|
|
49
|
+
### Thread Safety
|
|
50
|
+
|
|
51
|
+
All reads and writes to `@documents` are protected by a `Mutex`. The fastembed model is not Mutex-protected because `Fastembed::TextEmbedding` is itself thread-safe.
|
|
52
|
+
|
|
53
|
+
### Integration with robot_lab Memory
|
|
54
|
+
|
|
55
|
+
When `robot_lab-document_store` is loaded alongside `robot_lab`, the Memory class gains:
|
|
56
|
+
```ruby
|
|
57
|
+
memory.store_document(:key, text)
|
|
58
|
+
memory.search_documents("query", limit: 5)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Key Constraints
|
|
62
|
+
|
|
63
|
+
- Documents are stored entirely in memory — the store does not persist across process restarts.
|
|
64
|
+
- Keys are coerced to `Symbol`. Storing under the same key replaces the previous document.
|
|
65
|
+
- The TF-IDF fallback has no semantic understanding — "car" and "automobile" will not match. Use fastembed for production.
|
|
66
|
+
- `FASTEMBED_AVAILABLE` is set at load time and cannot be changed at runtime.
|
|
67
|
+
|
|
68
|
+
## Testing
|
|
69
|
+
|
|
70
|
+
- Minitest with SimpleCov (`minimum_coverage line: 95, branch: 75` enforced)
|
|
71
|
+
- Tests stub fastembed to avoid downloading the ONNX model — do not call the real fastembed model in unit tests
|
|
72
|
+
- Coverage: 98.89% line / 95.83% branch
|
data/Rakefile
CHANGED
|
@@ -24,16 +24,6 @@ task :test_file, [:file] do |_t, args|
|
|
|
24
24
|
ruby "test/#{args[:file]}"
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
desc 'Check code style with RuboCop'
|
|
28
|
-
task :rubocop do
|
|
29
|
-
sh 'bundle exec rubocop'
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
desc 'Auto-correct RuboCop offenses'
|
|
33
|
-
task :rubocop_fix do
|
|
34
|
-
sh 'bundle exec rubocop -a'
|
|
35
|
-
end
|
|
36
|
-
|
|
37
27
|
desc 'Check code complexity with Flog (warn >=20, fail >=50)'
|
|
38
28
|
task :flog_check do
|
|
39
29
|
require 'flog'
|
|
@@ -71,36 +61,62 @@ task :flog_check do
|
|
|
71
61
|
end
|
|
72
62
|
end
|
|
73
63
|
|
|
74
|
-
desc '
|
|
75
|
-
task :
|
|
76
|
-
|
|
64
|
+
desc 'Check for structural code duplication with Flay (mass >= 50)'
|
|
65
|
+
task :flay_check do
|
|
66
|
+
require 'flay'
|
|
77
67
|
|
|
78
|
-
|
|
79
|
-
puts 'Quality Gate: Tests + Coverage'
|
|
80
|
-
puts '=' * 60
|
|
81
|
-
results[:tests] = system('bundle exec rake test') ? :pass : :fail
|
|
68
|
+
mass_threshold = 50
|
|
82
69
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
results[:rubocop] = system('bundle exec rubocop') ? :pass : :fail
|
|
70
|
+
flay = Flay.new({ mass: mass_threshold, diff: false, verbose: false, summary: false, timeout: 60 })
|
|
71
|
+
flay.process(*Dir.glob('lib/**/*.rb'))
|
|
72
|
+
flay.analyze
|
|
87
73
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
74
|
+
if flay.hashes.empty?
|
|
75
|
+
puts "\nFlay: no structural duplication detected (mass >= #{mass_threshold})"
|
|
76
|
+
else
|
|
77
|
+
puts "\nFlay found structural duplication (mass >= #{mass_threshold}):"
|
|
78
|
+
flay.report
|
|
79
|
+
abort "\nFlay quality gate failed: #{flay.hashes.length} pattern(s) detected"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
desc 'Run all quality checks: tests (with coverage), RuboCop, Flog, and Flay'
|
|
84
|
+
task :quality do
|
|
85
|
+
gates = [
|
|
86
|
+
['Tests + Coverage', 'bundle exec rake test'],
|
|
87
|
+
['RuboCop', 'bundle exec rubocop'],
|
|
88
|
+
['Flog Complexity', 'bundle exec rake flog_check'],
|
|
89
|
+
['Flay Duplication', 'bundle exec rake flay_check']
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
results = gates.map do |label, command|
|
|
93
|
+
puts "\n#{'=' * 60}"
|
|
94
|
+
puts "Quality Gate: #{label}"
|
|
95
|
+
puts '=' * 60
|
|
96
|
+
[label, system(command) ? :pass : :fail]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
green = ->(s) { "\e[32m#{s}\e[0m" }
|
|
100
|
+
red = ->(s) { "\e[31m#{s}\e[0m" }
|
|
101
|
+
width = results.map { |label, _| label.length }.max
|
|
92
102
|
|
|
93
103
|
puts "\n#{'=' * 60}"
|
|
94
|
-
puts 'Quality Summary'
|
|
104
|
+
puts 'Quality Gate Summary'
|
|
95
105
|
puts '=' * 60
|
|
96
|
-
results.each do |
|
|
97
|
-
|
|
98
|
-
puts " [#{
|
|
106
|
+
results.each do |label, status|
|
|
107
|
+
badge = status == :pass ? green.call('PASS') : red.call('FAIL')
|
|
108
|
+
puts " [#{badge}] #{label.ljust(width)}"
|
|
99
109
|
end
|
|
110
|
+
puts '-' * 60
|
|
111
|
+
|
|
112
|
+
passed = results.count { |_, s| s == :pass }
|
|
113
|
+
failed = results.count { |_, s| s == :fail }
|
|
114
|
+
tally = "#{passed} passed, #{failed} failed"
|
|
115
|
+
puts " #{failed.zero? ? green.call(tally) : red.call(tally)}"
|
|
100
116
|
puts '=' * 60
|
|
101
117
|
|
|
102
|
-
abort "\
|
|
103
|
-
puts "\
|
|
118
|
+
abort "\n#{red.call('Quality gate failed.')}" unless failed.zero?
|
|
119
|
+
puts "\n#{green.call('All quality gates passed.')}"
|
|
104
120
|
end
|
|
105
121
|
|
|
106
122
|
namespace :docs do
|
data/docs/getting_started.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Prerequisites
|
|
4
4
|
|
|
5
|
-
- Ruby 3.
|
|
5
|
+
- Ruby 3.2+
|
|
6
6
|
- **fastembed** (recommended) — requires a platform that can run ONNX Runtime (x86_64 and ARM64 macOS/Linux). On first use the ~23 MB `BAAI/bge-small-en-v1.5` model file is downloaded and cached in `~/.cache/fastembed`.
|
|
7
7
|
- Without fastembed the store still works using the built-in TF-IDF fallback (see [Fallback Mode](#fallback-mode) below).
|
|
8
8
|
|
data/docs/how_it_works.md
CHANGED
|
@@ -64,7 +64,7 @@ term frequencies.
|
|
|
64
64
|
raw text
|
|
65
65
|
→ downcase
|
|
66
66
|
→ tokenise /[a-z]+/ (ASCII only — Unicode letters are dropped)
|
|
67
|
-
→ remove STOP_WORDS (
|
|
67
|
+
→ remove STOP_WORDS (45 common English words: a, an, the, is, are, …)
|
|
68
68
|
→ Porter-style stem (strips: -ies, -ness, -ment, -tion, -ing, -ed, -er, -ly, -s)
|
|
69
69
|
→ count term frequencies
|
|
70
70
|
→ L2-normalise counts (divide each count by the Euclidean norm of the count vector)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: robot_lab-document_store
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
@@ -50,8 +50,11 @@ extra_rdoc_files: []
|
|
|
50
50
|
files:
|
|
51
51
|
- ".envrc"
|
|
52
52
|
- ".github/workflows/deploy-github-pages.yml"
|
|
53
|
+
- ".loki"
|
|
54
|
+
- ".quality/reek_baseline.txt"
|
|
53
55
|
- ".rubocop.yml"
|
|
54
56
|
- CHANGELOG.md
|
|
57
|
+
- CLAUDE.md
|
|
55
58
|
- LICENSE.txt
|
|
56
59
|
- README.md
|
|
57
60
|
- Rakefile
|
|
@@ -93,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
93
96
|
- !ruby/object:Gem::Version
|
|
94
97
|
version: '0'
|
|
95
98
|
requirements: []
|
|
96
|
-
rubygems_version: 4.0.
|
|
99
|
+
rubygems_version: 4.0.17
|
|
97
100
|
specification_version: 4
|
|
98
101
|
summary: Embedding-based semantic document store for RobotLab agents
|
|
99
102
|
test_files: []
|