Module: Silas::Instructions
- Defined in:
- lib/silas/instructions.rb
Overview
Renders instructions.md ONCE per turn into an immutable snapshot — the determinism anchor. (Skill-index injection and loaded-skill inlining land with the skills work; the snapshot-once mechanics are load-bearing now.)
Class Method Summary collapse
- .base_instructions(turn) ⇒ Object
- .default_instructions ⇒ Object
-
.loaded_skills_block(session) ⇒ Object
Skills loaded in prior turns are inlined "for the rest of the session".
-
.memory_block(session) ⇒ Object
Recent memories surface into the snapshot (bounded; recall digs deeper).
- .render(turn) ⇒ Object
-
.skill_index_block(session) ⇒ Object
Advertise skill descriptions (eve's routing hint); bodies load on demand.
- .snapshot!(turn) ⇒ Object
Class Method Details
.base_instructions(turn) ⇒ Object
24 25 26 27 28 29 30 31 32 |
# File 'lib/silas/instructions.rb', line 24 def base_instructions(turn) # config.instructions_dir points at the active agent's directory (root or a # subagent, swapped during a nested run). dir = Silas.instructions_dir || Rails.root.join("app/agent") path = Pathname(dir).join("instructions.md") return default_instructions unless path.exist? ERB.new(path.read).result_with_hash(session: turn.session, agent_name: turn.session.agent_name) end |
.default_instructions ⇒ Object
63 64 65 |
# File 'lib/silas/instructions.rb', line 63 def default_instructions "You are a helpful agent." end |
.loaded_skills_block(session) ⇒ Object
Skills loaded in prior turns are inlined "for the rest of the session".
56 57 58 59 60 61 |
# File 'lib/silas/instructions.rb', line 56 def loaded_skills_block(session) loaded = Silas.skills.select { |s| session.loaded_skills.include?(s.name) } return nil if loaded.empty? loaded.map { |s| "## Skill: #{s.name}\n\n#{s.body.strip}" }.join("\n\n") end |
.memory_block(session) ⇒ Object
Recent memories surface into the snapshot (bounded; recall digs deeper).
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/silas/instructions.rb', line 35 def memory_block(session) return nil unless Silas.memory_enabled? memories = Silas::Memory.recall(agent_name: session.agent_name, limit: Silas.config.memory_injection_limit) return nil if memories.empty? "## Memory (most recent — use the recall tool for more)\n\n" + memories.map { |m| "- #{m.to_line}" }.join("\n") end |
.render(turn) ⇒ Object
19 20 21 22 |
# File 'lib/silas/instructions.rb', line 19 def render(turn) [ base_instructions(turn), memory_block(turn.session), skill_index_block(turn.session), loaded_skills_block(turn.session) ] .compact.join("\n\n") end |
.skill_index_block(session) ⇒ Object
Advertise skill descriptions (eve's routing hint); bodies load on demand.
47 48 49 50 51 52 53 |
# File 'lib/silas/instructions.rb', line 47 def skill_index_block(session) advertised = Silas.skills.reject { |s| session.loaded_skills.include?(s.name) } return nil if advertised.empty? lines = advertised.map { |s| "- #{s.name}: #{s.description}" } "## Available skills\n\nLoad with the load_skill tool when relevant:\n#{lines.join("\n")}" end |
.snapshot!(turn) ⇒ Object
10 11 12 13 14 15 16 17 |
# File 'lib/silas/instructions.rb', line 10 def snapshot!(turn) return if turn.instructions_snapshot.present? # idempotent: replay-safe turn.update!( instructions_snapshot: render(turn), definitions_digest: Silas.definitions_digest.to_s ) end |