fix(sona): expose find_patterns on EphemeralAgent + fix get_patterns returning empty#368
Open
shaal wants to merge 1 commit intoruvnet:mainfrom
Open
fix(sona): expose find_patterns on EphemeralAgent + fix get_patterns returning empty#368shaal wants to merge 1 commit intoruvnet:mainfrom
shaal wants to merge 1 commit intoruvnet:mainfrom
Conversation
…returning empty
`EphemeralAgent::get_patterns()` was calling `self.engine.find_patterns(&[], 0)` —
an empty-query / k=0 lookup that always returns `Vec::new()`. The shape of the
call makes it clear this was stub scaffolding rather than an intended behaviour.
Consumers calling `get_patterns()` silently received an empty list no matter how
many patterns the agent had accumulated.
The underlying `engine.find_patterns(query, k)` works correctly; the miss was
that it was never exposed as a public method on `EphemeralAgent`, so callers
had no way to actually query the reasoning bank for a top-k by similarity.
Changes (40 lines across two files):
1. crates/sona/src/training/federated.rs
- `get_patterns()` now delegates to `self.engine.get_all_patterns()` and
returns the full learned-pattern list.
- New public method `find_patterns(query: &[f32], k: usize)` forwards to
`self.engine.find_patterns(query, k)` so callers can do a cosine-ranked
top-k from a query embedding.
2. crates/sona/src/wasm.rs
- New `#[wasm_bindgen(js_name = findPatterns)]` binding on
`WasmEphemeralAgent` that accepts a Float32Array query vector and a k,
and returns the serialized `Vec<LearnedPattern>` via serde_wasm_bindgen
(matches the existing `getPatterns` pattern).
No behavioural change for existing callers of `getPatterns` beyond it now
returning the non-empty list it was presumably always meant to return.
Verified by vendoring the patched crate into a downstream consumer and
confirming `findPatterns(embedding, k)` round-trips a populated array with
the expected LearnedPattern shape; `getPatterns()` also now returns a
non-empty list when the agent has accumulated patterns.
7145a86 to
be020bc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #367.
The bug, briefly
EphemeralAgent::get_patterns()was written as:That inner call says "find me the top-0 patterns most similar to this empty query vector." Both halves are degenerate, so the engine dutifully returns
Vec::new(). Every time. The method silently reports that an ephemeral agent has learned nothing, even after the agent has observed and internalised many patterns.The underlying
engine.find_patterns(query, k)andengine.get_all_patterns()both work correctly — they just weren't reachable from theEphemeralAgentpublic surface. Issue #367 has the longer walk-through of how this manifests downstream (stats counters keep working, but the actual pattern list is always empty — very easy to miss).What this PR changes
Two files, 18 lines added, 1 removed.
crates/sona/src/training/federated.rsget_patterns()now delegates to the engine's "give me everything you've learned" method:…and a new public method forwards the engine's query-ranked top-k lookup so that callers who do want similarity-ranked results can ask for them directly rather than having to walk the full list and re-rank in their own code:
crates/sona/src/wasm.rsA
#[wasm_bindgen(js_name = findPatterns)]method onWasmEphemeralAgent, mirroring the existinggetPatternsbinding one level above it:Now JS consumers can call
agent.findPatterns(queryFloat32Array, k)and receive a populated array ofLearnedPatternobjects.Why surface a
find_patterns(query, k)at all, not just fixget_patterns()The narrow fix — swapping
find_patterns(&[], 0)forget_all_patterns()insideget_patterns()— would already stop the silent-empty-list behaviour. But the reason the engine has afind_patterns(query, k)method in the first place is that callers often want a similarity-ranked top-k (e.g. "what are the 5 patterns closest to this new observation?") rather than the full accumulated list. Hiding that capability behind a method that always returns everything forces consumers to reimplement ranking client-side over a potentially long pattern list. Exposingfind_patternsas its own method keepsget_patternshonest (returns everything) and lets the engine's existing ranked-retrieval do its job when needed. The two names now describe what they actually do.Backwards compatibility
get_patterns()/getPatterns()— signature unchanged; behaviour shifts from always empty to the correct, non-empty list. Callers who were tolerating the empty-list case will still compile; they'll just start receiving real data.find_patterns()/findPatterns()— brand-new names in both Rust and JS. No collisions with existing public API.No
Cargo.tomlor dependency changes. No schema changes toLearnedPattern.Verification done locally
I vendored the patched
sonacrate into a downstream consumer that exercises both methods from JS:WasmEphemeralAgentand let it accumulate patterns.getPatterns()— previously returned[]; now returns the expected populatedLearnedPattern[]with matchingget_stats().patternscount.findPatterns(queryEmbedding, 5)with a Float32Array query — returns a top-5LearnedPattern[]in similarity order, matching what a manual cosine re-ranking ofgetPatterns()produces.Open to shape adjustments
If you'd prefer a different API shape — for example deprecating
get_patterns()in favour offind_patterns(query, k)entirely, or renaming, or splitting into two traits — I'm happy to reshape. This PR picks the minimum-surprise option (fix the existing method's contract + add the missing sibling). Let me know what fits the sona public-surface direction best.