Repository navigation
feat(memory): BM25 memory search without an embedding model, searchable plugin data, and recorded facts - #177
Merged
Merged
Conversation
…searchable
Memory search needed an embedding model to do better than counting shared
words, and no default configuration has one. Without an embedding slot it now
ranks with BM25 over words and CJK character pairs, so a name outweighs a word
that every passage holds and a long passage is not put last for being long.
An embedding slot stays optional.
Kernel:
- `rankTexts`, `searchTerms` and `searchExcerpt` in the plugin SDK; the memory
package and plugins use the one implementation.
- Recall also ranks the history summaries, so a turn older than the latest
500 messages can be found.
- `contributes.data.<namespace>.search: { text }` puts a plugin namespace
into `memory-search` and the vector index while the plugin is active in
the session. A namespace without the declaration is not read.
memory plugin (0.0.36):
- Adds up to three facts of each turn to a `facts` namespace that is never
rewritten, and declares it searchable.
- The prompt segment brings back the earlier facts that the player's
message is about.
- A block over its limit is shortened by the model; it is cut at a sentence
end only when that fails.
A world's memory block can no longer take the label `new_facts`.
…p repeated facts A six-turn session with a real model showed three faults in the new facts. - A fact was recalled because it shared one everyday word with the player's message. A fact is now recalled when a fair part of the message's terms is about it, or when the message and the fact name the same character. Names are compared by their terms, so part of a name is enough. `rankTexts` returns `matched` for the first test. - The same event was recorded on two turns in a row. A new fact that shares most of its terms with a recorded one is not written, and the extraction prompt shows the latest recorded facts. - The player character's background and guesses were recorded as new facts. The prompt now names what is not a fact of the turn, and keeps a past event that is told for the first time.
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.
Summary / 摘要
Memory search did better than counting shared words only when an embedding model was configured, and no default configuration has one: neither
llm.toml.examplenor a fresh install defines an embedding slot, so the vector path never ran. Asking every player to host or pay for an embedding model is not acceptable, so this PR makes the path without one good, and keeps the embedding slot as an optional addition.Kernel: the search itself
rankTexts,searchTermsandsearchExcerptin@covel/plugin-handlers-utils: Okapi BM25 over words and CJK character pairs. A name outweighs a word that every passage holds, and a long passage is not put last for being long.@covel/memoryand plugins use the one implementation.contributes.data.<namespace>.search: { text: <field> }puts a plugin's namespace intomemory-search(sourcearchival:plugin_data) and into the vector index when one exists. The host resolves the list from the plugins active in the session; a namespace without the declaration is not read, and the kernel names no plugin.memory-searchdescription tells the caller that the search matches words, not meaning, and to give names and several wordings.memoryplugin (0.0.36): what to remember and when to bring it backfactsnamespace that is only added to; a block holds the present state and forgets, the facts keep what happened.Measured
codex/gpt-6-luna): the harness passed, every extraction job succeeded, facts were stored, a<recalled-facts>segment reached the narrator prompt, and the narrator calledmemory-searchwith names and several wordings. The first session showed three faults (recall on one everyday word, a fact recorded twice, the player's background recorded as a new fact); the third commit fixes them, checked against the stored data of that session and a second session.A world's memory block can no longer take the label
new_facts(it is the key of the facts in the extraction reply). No bundled world uses it, and no development data has to be recreated.Type of change / 变更类型
Verification / 验证方式
pnpm checkpnpm testpnpm test:pg— not run. The memory package reads through existingDataStoremethods (listSessionSummaries,listPluginData); no store code changed.pnpm e2e:smoke/pnpm e2e— not run; no UI change.pnpm validate:plugin plugins/memorypnpm e2e:verify— the harness script against an isolated server, two six-turn sessions, result PASS.memory-searchcall of both sessions intrace_events.Not verified / 未验证:
Related issue / context / 关联
docs/CHANGELOG.mdandpackages/plugin-handlers-utils/src/index.ts, which feat(ai-provider)!: provider catalog, protocol registry, plugin text protocols and OpenAI Decisions #176 also changes; whichever merges second needs a small conflict resolution there.searchmanifest field, and@covel/memorynow depending on@covel/plugin-handlers-utils(scripts/check-package-boundaries.mjs).Docs sync / 文档同步
docs/reference/updated for changed contracts, APIs, tools, or protocol —tools.md(memory-search),plugins.md(searchable data,rankTexts), regeneratedschema/plugin-manifest.md.docs/guide/plugin-authoring.md,docs/architecture/packages.md,plugins/memory/README.md; none of the changed pages has an.en.mdsibling.docs/CHANGELOG.mdhas an entry under[Unreleased]AGENTS.md— n/a: no new package or root script.