Class: TurnKit::OutputPolicy

Inherits:
Object
  • Object
show all
Defined in:
lib/turnkit/output_policy.rb

Constant Summary collapse

DEFAULT_SCHEMA =
{
  type: "object",
  properties: {
    approved: { type: "boolean" },
    violations: {
      type: "array",
      items: {
        type: "object",
        properties: {
          rule: { type: "string" },
          message: { type: "string" }
        },
        required: [ "rule", "message" ]
      }
    }
  },
  required: [ "approved", "violations" ]
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content:, name: "output_policy", model: nil, thinking: nil, client: nil) ⇒ OutputPolicy

Returns a new instance of OutputPolicy.

Raises:

  • (ArgumentError)


43
44
45
46
47
48
49
50
# File 'lib/turnkit/output_policy.rb', line 43

def initialize(content:, name: "output_policy", model: nil, thinking: nil, client: nil)
  @name = name.to_s
  @content = content.to_s
  @model = model
  @thinking = Agent.normalize_thinking(thinking)
  @client = client
  raise ArgumentError, "content is required" if @content.empty?
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



24
25
26
# File 'lib/turnkit/output_policy.rb', line 24

def client
  @client
end

#contentObject (readonly)

Returns the value of attribute content.



24
25
26
# File 'lib/turnkit/output_policy.rb', line 24

def content
  @content
end

#modelObject (readonly)

Returns the value of attribute model.



24
25
26
# File 'lib/turnkit/output_policy.rb', line 24

def model
  @model
end

#nameObject (readonly)

Returns the value of attribute name.



24
25
26
# File 'lib/turnkit/output_policy.rb', line 24

def name
  @name
end

#thinkingObject (readonly)

Returns the value of attribute thinking.



24
25
26
# File 'lib/turnkit/output_policy.rb', line 24

def thinking
  @thinking
end

Class Method Details

.from_file(path, name: nil, **options) ⇒ Object



26
27
28
# File 'lib/turnkit/output_policy.rb', line 26

def self.from_file(path, name: nil, **options)
  new(name: name || File.basename(path, File.extname(path)), content: File.read(path), **options)
end

.from_skill(skill, **options) ⇒ Object



30
31
32
# File 'lib/turnkit/output_policy.rb', line 30

def self.from_skill(skill, **options)
  new(name: skill.key, content: skill.content, **options)
end

.require_imageObject



34
35
36
37
38
39
40
41
# File 'lib/turnkit/output_policy.rb', line 34

def self.require_image
  lambda do |output, output_data: nil, turn: nil, **|
    data = output_data.is_a?(Hash) ? output_data : output
    images = data.is_a?(Hash) ? data["images"] || data[:images] : nil
    has_image = Array(images).any? || turn&.conversation&.messages_for_turn(turn)&.any?(&:image?)
    { rule: "image_required", message: "output must include an image result" } unless has_image
  end
end

Instance Method Details

#call(output, run: nil, turn: nil) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/turnkit/output_policy.rb', line 52

def call(output, run: nil, turn: nil)
  model_name = model || turn&.model || run&.turn&.model || TurnKit.default_model
  result = if turn
    turn.internal_model_call(
      model: model_name,
      messages: audit_messages(output),
      tools: [],
      instructions: audit_instructions,
      thinking: thinking,
      output_schema: DEFAULT_SCHEMA,
      metadata: { output_policy: name },
      purpose: "output_policy",
      client: client
    )
  else
    audit_client = client || TurnKit.client
    audit_client.validate!(model: model_name)
    chat(audit_client, model: model_name, messages: audit_messages(output), tools: [], instructions: audit_instructions, thinking: thinking, output_schema: DEFAULT_SCHEMA, metadata: { output_policy: name })
  end
  data = result.output_data || parse_json(result.text)
  return if data.fetch("approved", false)

  Array(data["violations"]).map do |violation|
    attrs = violation.transform_keys(&:to_s)
    OutputAudit::Violation.new(
      rule: attrs["rule"] || name,
      message: attrs["message"] || "output policy failed",
      metadata: attrs.reject { |key, _| %w[rule message].include?(key) }
    )
  end
end