Class: Kernai::SkillResult

Inherits:
Object
  • Object
show all
Defined in:
lib/kernai/skill_result.rb

Overview

Rich return shape for a skill’s ‘execute` block. Lets the skill carry three distinct pieces of information back to the kernel:

- `text`     → the message the LLM will see (injected in a
               <block type="result" name="..."> wrapper)
- `media`    → one or more Kernai::Media parts (spliced in as
               <block type="media"/> references after the text)
- `metadata` → free-form hash attached to the :skill_result recorder
               entry. Never shown to the LLM; useful for scoring,
               timings, structured status codes, etc.

Skills are NOT required to return a SkillResult — the legacy return shapes (String, Media, Array<String|Media>, nil, other) remain fully supported. Use SkillResult only when you need the metadata side-channel or when it reads more clearly than a raw string.

Normalisation utilities for ANY return shape live as class methods on this class (‘.wrap`, `.metadata_of`) so callers only have to know about one name.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text: '', media: nil, metadata: nil) ⇒ SkillResult

Returns a new instance of SkillResult.



26
27
28
29
30
# File 'lib/kernai/skill_result.rb', line 26

def initialize(text: '', media: nil, metadata: nil)
  @text = text.to_s
  @media = Array(media).compact
  @metadata =  || {}
end

Instance Attribute Details

#mediaObject (readonly)

Returns the value of attribute media.



24
25
26
# File 'lib/kernai/skill_result.rb', line 24

def media
  @media
end

#metadataObject (readonly)

Returns the value of attribute metadata.



24
25
26
# File 'lib/kernai/skill_result.rb', line 24

def 
  @metadata
end

#textObject (readonly)

Returns the value of attribute text.



24
25
26
# File 'lib/kernai/skill_result.rb', line 24

def text
  @text
end

Class Method Details

.coerce(part) ⇒ Object



83
84
85
86
87
88
# File 'lib/kernai/skill_result.rb', line 83

def self.coerce(part)
  case part
  when String, Media then part
  else part.to_s
  end
end

.metadata_of(value) ⇒ Object

Extract observability metadata from a skill return value. Only explicit SkillResult instances carry metadata; every other return shape yields an empty hash. Providers / the kernel call this without having to introspect the return type themselves.



53
54
55
# File 'lib/kernai/skill_result.rb', line 53

def self.(value)
  value.is_a?(SkillResult) ? value. : {}
end

.normalise(value) ⇒ Object



72
73
74
75
76
77
78
79
80
81
# File 'lib/kernai/skill_result.rb', line 72

def self.normalise(value)
  case value
  when nil         then ['']
  when String      then [value]
  when Media       then [value]
  when Array       then value.map { |p| coerce(p) }
  when SkillResult then [value.text, *value.media]
  else [value.to_s]
  end
end

.text_of(value) ⇒ Object

Extract the text payload from a skill return value — what ends up in the LLM-facing <block type=“result”> wrapper. Defined as the counterpart to ‘metadata_of` so the kernel can log “what the LLM saw” cleanly.



61
62
63
64
65
66
67
68
69
70
# File 'lib/kernai/skill_result.rb', line 61

def self.text_of(value)
  case value
  when nil         then ''
  when SkillResult then value.text
  when String      then value
  when Media       then ''
  when Array       then value.grep(String).join
  else value.to_s
  end
end

.wrap(value, store) ⇒ Object

Turn whatever a Skill’s execute block returned into a canonical list of parts the kernel can splice back into the conversation. Media parts are side-registered in the context’s MediaStore so other components (skills, workflow consumers, recorders) can look them up by id without having to pass the object around.



43
44
45
46
47
# File 'lib/kernai/skill_result.rb', line 43

def self.wrap(value, store)
  parts = normalise(value)
  parts.each { |p| store.put(p) if p.is_a?(Media) }
  parts
end

Instance Method Details

#to_hObject



32
33
34
# File 'lib/kernai/skill_result.rb', line 32

def to_h
  { text: @text, media: @media.map(&:to_h), metadata: @metadata }
end