Class: Legion::Extensions::Llm::Canonical::Request

Inherits:
Data
  • Object
show all
Defined in:
lib/legion/extensions/llm/canonical/request.rb

Overview

Canonical request shape — the single contract between client translators and the inference executor. Per R3 and G18. # -- required for Data.define block scope

Constant Summary collapse

BUILD_SITE =
'Canonical::Request.build'
FROM_HASH_SITE =
'Canonical::Request.from_hash'
NEW_SITE =
'Canonical::Request.new'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#callerObject (readonly)

Returns the value of attribute caller

Returns:

  • (Object)

    the current value of caller



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def caller
  @caller
end

#conversation_idObject (readonly)

Returns the value of attribute conversation_id

Returns:

  • (Object)

    the current value of conversation_id



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def conversation_id
  @conversation_id
end

#idObject (readonly)

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def id
  @id
end

#messagesObject (readonly)

Returns the value of attribute messages

Returns:

  • (Object)

    the current value of messages



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def messages
  @messages
end

#metadataObject (readonly)

Returns the value of attribute metadata

Returns:

  • (Object)

    the current value of metadata



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def 
  @metadata
end

#paramsObject (readonly)

Returns the value of attribute params

Returns:

  • (Object)

    the current value of params



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def params
  @params
end

#routingObject (readonly)

Returns the value of attribute routing

Returns:

  • (Object)

    the current value of routing



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def routing
  @routing
end

#streamObject (readonly)

Returns the value of attribute stream

Returns:

  • (Object)

    the current value of stream



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def stream
  @stream
end

#systemObject (readonly)

Returns the value of attribute system

Returns:

  • (Object)

    the current value of system



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def system
  @system
end

#thinkingObject (readonly)

Returns the value of attribute thinking

Returns:

  • (Object)

    the current value of thinking



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def thinking
  @thinking
end

#tool_choiceObject (readonly)

Returns the value of attribute tool_choice

Returns:

  • (Object)

    the current value of tool_choice



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def tool_choice
  @tool_choice
end

#toolsObject (readonly)

Returns the value of attribute tools

Returns:

  • (Object)

    the current value of tools



12
13
14
# File 'lib/legion/extensions/llm/canonical/request.rb', line 12

def tools
  @tools
end

Class Method Details

.build(id: nil, messages: nil, system: nil, tools: nil, tool_choice: nil, params: nil, thinking: nil, stream: false, conversation_id: nil, caller: nil, routing: nil, metadata: {}) ⇒ Object

Build from keyword args (primary constructor).



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/legion/extensions/llm/canonical/request.rb', line 18

def self.build(
  id: nil, messages: nil, system: nil, tools: nil, tool_choice: nil,
  params: nil, thinking: nil, stream: false,
  conversation_id: nil, caller: nil, routing: nil, metadata: {}
)
  new(
    id: id || "req_#{SecureRandom.hex(12)}",
    messages: normalize_messages!(messages, self::BUILD_SITE),
    system: system,
    tools: normalize_tools(tools, self::BUILD_SITE),
    tool_choice: tool_choice.is_a?(::String) ? tool_choice.to_sym : tool_choice,
    params: normalize_params!(params, self::BUILD_SITE),
    thinking: normalize_thinking!(thinking, self::BUILD_SITE),
    stream: stream,
    conversation_id: conversation_id,
    caller: caller,
    routing: routing || {},
    metadata: Strict.metadata!(, self::BUILD_SITE)
  )
end

.from_hash(source) ⇒ Object

Build from a Hash (raw client request or deserialized wire payload). Unknown keys fold into metadata — the model for 04 L5.



41
42
43
44
45
46
# File 'lib/legion/extensions/llm/canonical/request.rb', line 41

def self.from_hash(source)
  Strict.require_hash!(source, self::FROM_HASH_SITE)
  hash = Strict.symbolize_keys(source)
   = Strict.fold_unknowns!(self, self::FROM_HASH_SITE, hash)
  build(**hash, metadata:)
end

.normalize_messages!(messages, site) ⇒ Object

04 §9: strict message map — each element must be a Message (pass) or a Hash (normalize); anything else raises. No silent drops (F2 fix).



50
51
52
53
54
55
# File 'lib/legion/extensions/llm/canonical/request.rb', line 50

def self.normalize_messages!(messages, site)
  return [] if messages.nil?

  Strict.expect_type!(messages, [::Array], site, :messages)
  messages.map { |msg| msg.is_a?(Message) ? msg : Message.from_hash(msg) }
end

.normalize_params!(params, site) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/legion/extensions/llm/canonical/request.rb', line 75

def self.normalize_params!(params, site)
  return nil if params.nil?
  return params if params.is_a?(Params)

  Strict.expect_type!(params, [::Hash], site, :params)
  Params.from_hash(params)
end

.normalize_thinking!(thinking, site) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/legion/extensions/llm/canonical/request.rb', line 83

def self.normalize_thinking!(thinking, site)
  return nil if thinking.nil?
  return thinking if thinking.is_a?(Thinking::Config)

  Strict.expect_type!(thinking, [::Hash], site, :thinking)
  Thinking::Config.from_hash(thinking)
end

.normalize_tools(tools, site) ⇒ Object

L2: the single tools normalizer, shared by build and from_hash. Hash<name, ToolDefinition> or Array<ToolDefinition|Hash>; anything else raises.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/legion/extensions/llm/canonical/request.rb', line 59

def self.normalize_tools(tools, site)
  return {} if tools.nil? || tools.empty?

  case tools
  when Hash
    tools.transform_values { |tool| tool.is_a?(ToolDefinition) ? tool : ToolDefinition.from_hash(tool) }
  when Array
    tools.each_with_object({}) do |tool, hash|
      td = tool.is_a?(ToolDefinition) ? tool : ToolDefinition.from_hash(tool)
      hash[td.name] = td
    end
  else
    Strict.expect_type!(tools, [::Hash, ::Array], site, :tools)
  end
end

Instance Method Details

#as_jsonObject

MultiJson/Oj/::JSON callback — prevents Data.define #inspect leak into JSON.



110
111
112
# File 'lib/legion/extensions/llm/canonical/request.rb', line 110

def as_json(*)
  to_h
end

#to_hObject

Serialize to a Hash for AMQP/fleet/wire transport.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/legion/extensions/llm/canonical/request.rb', line 92

def to_h
  {
    id: id,
    messages: messages&.map { |m| m.is_a?(Message) ? m.to_h : m },
    system: system,
    tools: tools&.transform_values { |t| t.is_a?(ToolDefinition) ? t.to_h : t },
    tool_choice: tool_choice,
    params: params&.to_h,
    thinking: thinking&.to_h,
    stream: stream,
    conversation_id: conversation_id,
    caller: caller,
    routing: routing,
    metadata: 
  }.compact
end

#to_jsonObject



114
115
116
# File 'lib/legion/extensions/llm/canonical/request.rb', line 114

def to_json(*)
  to_h.to_json(*)
end