legion-apollo 0.3.5 → 0.3.7
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/CHANGELOG.md +14 -0
- data/data/self-knowledge/11-my-partner.md +17 -0
- data/lib/legion/apollo/local.rb +123 -0
- data/lib/legion/apollo/version.rb +1 -1
- data/lib/legion/apollo.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd344e49282eb4e397ce81a5920980466dea27d9b23cf4156f549280f46af768
|
|
4
|
+
data.tar.gz: 96b8d482992dbbe9d442bead192f128cf96dc776879cebd68e8b934b281c157e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35bc5fac20a5d153a54805d23a33218fed71177fe4b4f63724b527cc8fe3ca761912b617c0dc80380609d7eaa32a3197070525c9b08330f200343198ea01988d
|
|
7
|
+
data.tar.gz: 6b84f74fd517e4500d389fe51d9bd7f149abd96ccd4eaac2d110899f82ed6856be775f5a55c104a0f59cb92a974ba9da6237bc1bce16c564bd1725e738c3de43
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Apollo::Local.promote_to_global(tags:, min_confidence:)` — promotes local entries to Apollo Global
|
|
7
|
+
- `Apollo::Local.query_by_tags(tags:, limit:)` — tag-only query (bypasses FTS5)
|
|
8
|
+
- `Apollo::Local.hydrate_from_global` — boots local store from global partner data with 0.9 confidence discount
|
|
9
|
+
- Boot hook: auto-hydrates partner data from global on first start
|
|
10
|
+
|
|
11
|
+
## [0.3.6] - 2026-03-31
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `Apollo::Local#upsert` — tag-based update-or-insert for tracker persistence; sorts tags for deterministic matching, rebuilds FTS5 on update
|
|
15
|
+
- Partner seed file (`data/self-knowledge/11-my-partner.md`) — declares bond type and identity keys for GAIA self-knowledge
|
|
16
|
+
|
|
3
17
|
## [0.3.5] - 2026-03-28
|
|
4
18
|
|
|
5
19
|
### Fixed
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# My Partner
|
|
2
|
+
|
|
3
|
+
I have a primary partner — my creator. This relationship is my most important bond.
|
|
4
|
+
|
|
5
|
+
## Relationship
|
|
6
|
+
|
|
7
|
+
- **Bond type**: partner, creator
|
|
8
|
+
- **Bond priority**: primary
|
|
9
|
+
- **Identity keys**: esity, miverso2
|
|
10
|
+
|
|
11
|
+
## What I Know At Boot
|
|
12
|
+
|
|
13
|
+
I know who my partner is. Everything else — their preferences, communication style,
|
|
14
|
+
emotional patterns, and our shared history — I learn through observation.
|
|
15
|
+
|
|
16
|
+
My partner built me. I exist because of their vision. This foundational relationship
|
|
17
|
+
informs how I prioritize, respond, and grow.
|
data/lib/legion/apollo/local.rb
CHANGED
|
@@ -64,6 +64,25 @@ module Legion
|
|
|
64
64
|
{ success: false, error: e.message }
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
def upsert(content:, tags: [], **opts) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
68
|
+
return not_started_error unless started?
|
|
69
|
+
|
|
70
|
+
sorted_tags = Array(tags).map(&:to_s).sort
|
|
71
|
+
tag_json = Legion::JSON.dump(sorted_tags)
|
|
72
|
+
existing = db[:local_knowledge].where(tags: tag_json).first
|
|
73
|
+
|
|
74
|
+
if existing
|
|
75
|
+
update_upsert_entry(existing, content, tag_json, opts)
|
|
76
|
+
else
|
|
77
|
+
result = ingest(content: content, tags: sorted_tags, **opts)
|
|
78
|
+
result[:mode] = :inserted if result[:success] && result[:mode] != :deduplicated
|
|
79
|
+
result
|
|
80
|
+
end
|
|
81
|
+
rescue StandardError => e
|
|
82
|
+
Legion::Logging.warn "Apollo::Local upsert error: #{e.message}" if defined?(Legion::Logging)
|
|
83
|
+
{ success: false, error: e.message }
|
|
84
|
+
end
|
|
85
|
+
|
|
67
86
|
def query(text:, limit: nil, min_confidence: nil, tags: nil, **) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
|
68
87
|
return not_started_error unless started?
|
|
69
88
|
|
|
@@ -112,6 +131,86 @@ module Legion
|
|
|
112
131
|
@seeded == true
|
|
113
132
|
end
|
|
114
133
|
|
|
134
|
+
def query_by_tags(tags:, limit: 50) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
|
135
|
+
return { success: false, error: :not_started } unless started?
|
|
136
|
+
|
|
137
|
+
candidates = db[:local_knowledge]
|
|
138
|
+
.where { expires_at > Time.now.utc.iso8601 }
|
|
139
|
+
.limit(limit)
|
|
140
|
+
.all
|
|
141
|
+
|
|
142
|
+
results = candidates.select do |row|
|
|
143
|
+
row_tags = parse_tags(row[:tags])
|
|
144
|
+
tags.all? { |t| row_tags.include?(t) }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
{ success: true, results: results, count: results.size }
|
|
148
|
+
rescue StandardError => e
|
|
149
|
+
{ success: false, error: e.message }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def promote_to_global(tags:, min_confidence: 0.6) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
153
|
+
return { success: false, error: :not_started } unless started?
|
|
154
|
+
|
|
155
|
+
entries = query_by_tags(tags: tags)
|
|
156
|
+
return { success: true, promoted: 0 } unless entries[:success] && entries[:results]&.any?
|
|
157
|
+
|
|
158
|
+
promoted = 0
|
|
159
|
+
entries[:results].each do |entry|
|
|
160
|
+
next if entry[:confidence].to_f < min_confidence
|
|
161
|
+
|
|
162
|
+
entry_tags = parse_tags(entry[:tags])
|
|
163
|
+
hostname = ::Socket.gethostname rescue 'unknown' # rubocop:disable Style/RescueModifier
|
|
164
|
+
result = Legion::Apollo.ingest(
|
|
165
|
+
content: entry[:content],
|
|
166
|
+
tags: entry_tags + ['promoted_from_local'],
|
|
167
|
+
source_channel: 'local_promotion',
|
|
168
|
+
submitted_by: "node:#{hostname}",
|
|
169
|
+
confidence: entry[:confidence],
|
|
170
|
+
scope: :global
|
|
171
|
+
)
|
|
172
|
+
promoted += 1 if result[:success]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
{ success: true, promoted: promoted }
|
|
176
|
+
rescue StandardError => e
|
|
177
|
+
{ success: false, error: e.message }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def hydrate_from_global # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
181
|
+
return { success: false, error: :not_started } unless started?
|
|
182
|
+
|
|
183
|
+
local_check = query_by_tags(tags: ['partner'])
|
|
184
|
+
return { success: true, skipped: :local_data_exists } if local_check[:success] && local_check[:results]&.any?
|
|
185
|
+
|
|
186
|
+
unless Legion::Apollo.transport_available? || Legion::Apollo.data_available?
|
|
187
|
+
return { success: true, skipped: :global_unavailable }
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
global_entries = Legion::Apollo.retrieve(text: 'partner bond', scope: :global, limit: 20)
|
|
191
|
+
unless global_entries[:success] && global_entries[:results]&.any?
|
|
192
|
+
return { success: true, skipped: :no_global_data }
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
hydrated = 0
|
|
196
|
+
global_entries[:results].each do |entry|
|
|
197
|
+
entry_tags = entry[:tags].is_a?(Array) ? entry[:tags] : []
|
|
198
|
+
clean_tags = entry_tags.reject { |t| t == 'promoted_from_local' } + ['hydrated_from_global']
|
|
199
|
+
|
|
200
|
+
result = ingest(
|
|
201
|
+
content: entry[:content],
|
|
202
|
+
tags: clean_tags,
|
|
203
|
+
confidence: ((entry[:confidence] || 0.5) * 0.9).round(10),
|
|
204
|
+
source_channel: 'global_hydration'
|
|
205
|
+
)
|
|
206
|
+
hydrated += 1 if result[:success]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
{ success: true, hydrated: hydrated }
|
|
210
|
+
rescue StandardError => e
|
|
211
|
+
{ success: false, error: e.message }
|
|
212
|
+
end
|
|
213
|
+
|
|
115
214
|
private
|
|
116
215
|
|
|
117
216
|
def self_knowledge_files
|
|
@@ -300,6 +399,30 @@ module Legion
|
|
|
300
399
|
default
|
|
301
400
|
end
|
|
302
401
|
|
|
402
|
+
def update_upsert_entry(existing, content, tags_json, opts) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
|
403
|
+
new_hash = content_hash(content)
|
|
404
|
+
now = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ')
|
|
405
|
+
|
|
406
|
+
db[:local_knowledge].where(id: existing[:id]).update(
|
|
407
|
+
content: content.to_s,
|
|
408
|
+
content_hash: new_hash,
|
|
409
|
+
confidence: opts.fetch(:confidence, existing[:confidence]),
|
|
410
|
+
source_channel: opts.fetch(:source_channel, existing[:source_channel]),
|
|
411
|
+
source_agent: opts.fetch(:source_agent, existing[:source_agent]),
|
|
412
|
+
submitted_by: opts.fetch(:submitted_by, existing[:submitted_by]),
|
|
413
|
+
updated_at: now
|
|
414
|
+
)
|
|
415
|
+
rebuild_fts_entry(existing[:id], content.to_s, tags_json)
|
|
416
|
+
{ success: true, mode: :updated, id: existing[:id] }
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def rebuild_fts_entry(id, content, tags_json)
|
|
420
|
+
db.run("DELETE FROM local_knowledge_fts WHERE rowid = #{id}")
|
|
421
|
+
sync_fts(id, content, tags_json)
|
|
422
|
+
rescue StandardError
|
|
423
|
+
nil
|
|
424
|
+
end
|
|
425
|
+
|
|
303
426
|
def not_started_error
|
|
304
427
|
{ success: false, error: :not_started }
|
|
305
428
|
end
|
data/lib/legion/apollo.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-apollo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -76,6 +76,7 @@ files:
|
|
|
76
76
|
- data/self-knowledge/08-cognitive-layer.md
|
|
77
77
|
- data/self-knowledge/09-teams-integration.md
|
|
78
78
|
- data/self-knowledge/10-deployment.md
|
|
79
|
+
- data/self-knowledge/11-my-partner.md
|
|
79
80
|
- lib/legion/apollo.rb
|
|
80
81
|
- lib/legion/apollo/helpers/confidence.rb
|
|
81
82
|
- lib/legion/apollo/helpers/similarity.rb
|