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

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.config.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_instructionsObject



51
52
53
# File 'lib/silas/instructions.rb', line 51

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".



44
45
46
47
48
49
# File 'lib/silas/instructions.rb', line 44

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

.render(turn) ⇒ Object



19
20
21
22
# File 'lib/silas/instructions.rb', line 19

def render(turn)
  [ base_instructions(turn), 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.



35
36
37
38
39
40
41
# File 'lib/silas/instructions.rb', line 35

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.config.definitions_digest&.call.to_s
  )
end