Class: SolidLoop::Dialects::Anthropic

Inherits:
Object
  • Object
show all
Defined in:
app/services/solid_loop/dialects/anthropic.rb

Instance Method Summary collapse

Instance Method Details

#apply_reasoning_strategies!(messages, strategies) ⇒ Object



16
17
18
19
20
21
22
23
# File 'app/services/solid_loop/dialects/anthropic.rb', line 16

def apply_reasoning_strategies!(messages, strategies)
  return unless messages.is_a?(Array)

  filtered = strategies.reject { |s| s == :gemini_signed }
  messages.each do |msg|
    SolidLoop::Dialects::ReasoningPacker.pack(msg, filtered)
  end
end

#auth_headers(api_token) ⇒ Object



10
11
12
13
14
# File 'app/services/solid_loop/dialects/anthropic.rb', line 10

def auth_headers(api_token)
  h = { "anthropic-version" => "2023-06-01" }
  h["x-api-key"] = api_token if api_token.present?
  h
end

#completion_url(base_url) ⇒ Object



6
7
8
# File 'app/services/solid_loop/dialects/anthropic.rb', line 6

def completion_url(base_url)
  base_url.to_s.gsub(/\/+$/, "") + "/v1/messages"
end

#extract_message_data(data) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/services/solid_loop/dialects/anthropic.rb', line 48

def extract_message_data(data)
  content_blocks = data["content"] || []

  text_block    = content_blocks.find { |b| b["type"] == "text" }
  thinking_block = content_blocks.find { |b| b["type"] == "thinking" }
  tool_blocks   = content_blocks.select { |b| b["type"] == "tool_use" }

  {
    content:    text_block&.dig("text"),
    reasoning:  thinking_block&.dig("thinking"),
    tool_calls: map_tool_calls(tool_blocks)
  }
end

#normalize_response(data, fallback_text: "", fallback_messages_text: "") ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/services/solid_loop/dialects/anthropic.rb', line 62

def normalize_response(data, fallback_text: "", fallback_messages_text: "")
  res = extract_message_data(data)

  usage_data =
    if data["usage"].is_a?(Hash)
      SolidLoop::LlmUsageParser::Anthropic.call(data["usage"])
    else
      SolidLoop::LlmUsageParser.estimate(fallback_text, fallback_messages_text)
    end

  {
    content:    res[:content],
    reasoning:  res[:reasoning],
    tool_calls: res[:tool_calls],
    usage:      usage_data,
    metadata:   { "model" => data["model"].presence }.compact
  }
end

#render_payload(payload) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'app/services/solid_loop/dialects/anthropic.rb', line 25

def render_payload(payload)
  messages = payload[:messages] || []

  # Extract system message — Anthropic puts it outside messages array
  system_msg = messages.find { |m| m[:role] == "system" }
  non_system  = messages.reject { |m| m[:role] == "system" }

  anthropic_payload = {
    model:      payload[:model],
    max_tokens: payload[:max_tokens] || 8096,
    messages:   merge_tool_results(non_system.map { |m| map_message(m) })
  }.compact

  anthropic_payload[:system]      = system_msg[:content] if system_msg
  anthropic_payload[:temperature] = payload[:temperature] if payload[:temperature]

  if payload[:tools]&.any?
    anthropic_payload[:tools] = payload[:tools].map { |t| map_tool(t) }
  end

  anthropic_payload
end