Class: Crystil::Wrappers::Google

Inherits:
Object
  • Object
show all
Defined in:
lib/crystil/wrappers/google.rb,
sig/crystil/wrappers/google.rbs

Overview

Wrapper for Google GenerativeAI Ruby client (google-genai library version 0.1)

Instance Method Summary collapse

Constructor Details

#initialize(config, collector, sentinel = nil) ⇒ Google

Returns a new instance of Google.

Parameters:



9
10
11
12
13
# File 'lib/crystil/wrappers/google.rb', line 9

def initialize(config, collector, sentinel = nil)
  @config = config
  @collector = collector
  @sentinel = sentinel
end

Instance Method Details

#patch_response_class!void

This method returns an undefined value.

Monkey-patch the GenerateContentResponse class to include missing fields



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/crystil/wrappers/google.rb', line 46

def patch_response_class!
  # Check if the constant exists and hasn't been patched yet
  return unless defined?(::Google::Genai::Types::GenerateContentResponse)
  return if ::Google::Genai::Types::GenerateContentResponse.instance_variable_defined?(:@_crystil_patched)

  ::Google::Genai::Types::GenerateContentResponse.class_eval do
    # camelCase intentional — these names must match Google's API response
    # keys verbatim so the patched accessors survive serialization through
    # `Base#extract_response`.
    attr_accessor :modelVersion, :usageMetadata, :responseId, :createTime # rubocop:disable Naming/MethodName
  end

  ::Google::Genai::Types::GenerateContentResponse.instance_variable_set(:@_crystil_patched, true)
end

#register(client) ⇒ Object

Parameters:

  • client (Object)

Returns:

  • (Object)


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/crystil/wrappers/google.rb', line 15

def register(client)
  validate_client!(client)

  # Prevent double registration
  return client if client.instance_variable_defined?(:@crystil_registered)

  # Patch response class after client is validated (ensures gem is loaded)
  patch_response_class!

  # Store references in client instance
  client.instance_variable_set(:@crystil_config, @config)
  client.instance_variable_set(:@crystil_collector, @collector)
  client.instance_variable_set(:@crystil_sentinel, @sentinel)
  client.instance_variable_set(:@crystil_registered, true)

  # Wrap the generate_content method
  wrap_generate_content_method(client)

  client
end

#validate_client!(client) ⇒ void

This method returns an undefined value.

Parameters:

  • client (Object)

Raises:



38
39
40
41
42
43
# File 'lib/crystil/wrappers/google.rb', line 38

def validate_client!(client)
  return if client.respond_to?(:models)

  raise RegistrationError,
        "Client does not appear to be a valid Google GenAI client (missing models method)"
end

#wrap_generate_content_method(client) ⇒ void

This method returns an undefined value.

Parameters:

  • client (Object)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/crystil/wrappers/google.rb', line 61

def wrap_generate_content_method(client)
  # Get the models resource
  models_resource = client.models

  # Store references on the models resource (needed for Base module)
  models_resource.instance_variable_set(:@crystil_config, client.instance_variable_get(:@crystil_config))
  models_resource.instance_variable_set(:@crystil_collector, client.instance_variable_get(:@crystil_collector))
  models_resource.instance_variable_set(:@crystil_sentinel, client.instance_variable_get(:@crystil_sentinel))

  # Store the original generate_content method
  original_generate_content = models_resource.method(:generate_content)

  # Wrap the generate_content method
  models_resource.define_singleton_method(:generate_content) do |*args, **kwargs, &block|
    # Include Base module methods
    extend Base unless singleton_class.include?(Base)

    start_time = Time.now
    version = defined?(::Google::Genai::VERSION) ? ::Google::Genai::VERSION : nil

    # Extract parameters for analytics
    params = kwargs.any? ? kwargs : (args.first || {})

    sentinel = instance_variable_get(:@crystil_sentinel)
    sentinel&.raise_if_irrelevant!(
      title: GOOGLE_CLIENT_TITLE,
      request: params,
      version: version
    )

    # Call original method
    response = if kwargs.any?
                 original_generate_content.call(**kwargs, &block)
               else
                 original_generate_content.call(*args, &block)
               end

    # Submit analytics
    crystil_submit_analytics(
      method: :generate_content,
      args: args,
      kwargs: params,
      response: response,
      start_time: start_time,
      end_time: Time.now,
      title: GOOGLE_CLIENT_TITLE,
      version: version
    )

    response
  rescue CrystilRequestInterceptedError => e
    # We don't want to send intercepts to collector
    raise e
  rescue StandardError => e
    params = kwargs.any? ? kwargs : (args.first || {})

    crystil_submit_error_analytics(
      method: :generate_content,
      args: args,
      kwargs: params,
      error: e,
      start_time: start_time,
      end_time: Time.now,
      title: GOOGLE_CLIENT_TITLE,
      version: version
    )

    raise e
  end
end