Class: Llmemory::SkillMining::Miner
- Inherits:
-
Object
- Object
- Llmemory::SkillMining::Miner
- Defined in:
- lib/llmemory/skill_mining/miner.rb
Overview
Skill mining scans an agent’s recent episodes (episodic memory) for repeated, successful trajectories and distills them into reusable skills (procedural memory). This is Voyager’s actual contribution: rather than a passive, hand-written skill library, procedural memory grows from lived experience.
Mining is human-in-the-loop by default: ‘mine` returns skill proposals and writes nothing. Pass `auto_register: true` to register them directly. Each registered skill carries provenance { method: “skill_mining”, sources: [{ type: “episode”, id: … }] } so it stays traceable to the experiences it was distilled from.
‘procedural` must respond to:
register_skill(name:, body:, description:, kind:, provenance:)
Constant Summary collapse
- DEFAULT_WINDOW =
20- DEFAULT_CONFIDENCE =
0.5- VALID_KINDS =
%w[prompt template code].freeze
Instance Method Summary collapse
-
#initialize(episodic:, procedural:, llm: nil) ⇒ Miner
constructor
A new instance of Miner.
-
#mine(window: DEFAULT_WINDOW, outcomes: nil, auto_register: false) ⇒ Object
Mines the most recent ‘window` episodes for reusable skills.
Constructor Details
Instance Method Details
#mine(window: DEFAULT_WINDOW, outcomes: nil, auto_register: false) ⇒ Object
Mines the most recent ‘window` episodes for reusable skills. When `outcomes` (an allowlist of outcome labels) is given, only episodes whose outcome is in the set are considered — a deterministic pre-filter.
Returns an array of proposal hashes ({ name:, kind:, body:, description:, confidence: }). When ‘auto_register: true`, registers each proposal and returns the new skill ids instead.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/llmemory/skill_mining/miner.rb', line 40 def mine(window: DEFAULT_WINDOW, outcomes: nil, auto_register: false) result = [] Llmemory::Instrumentation.instrument(:mine_skills, window: window, auto_register: auto_register) do episodes = @episodic.recent_episodes(limit: window) episodes = filter_by_outcome(episodes, outcomes) if outcomes next if episodes.empty? proposals = distill(episodes) next if proposals.empty? result = auto_register ? register(proposals, episodes) : proposals end result end |