Skip to content

Commit ddb3281

Browse files
authored
fix(sdk): proper support for gemini (#8)
1 parent 22a2602 commit ddb3281

6 files changed

Lines changed: 118 additions & 31 deletions

File tree

sample-app/Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ source "https://rubygems.org"
44

55
gem "ruby-openai"
66
gem "traceloop-sdk"
7+
8+
gem "gemini-ai", "~> 4.1"

sample-app/Gemfile.lock

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,56 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4+
addressable (2.8.7)
5+
public_suffix (>= 2.0.2, < 7.0)
46
base64 (0.1.1)
5-
event_stream_parser (0.3.0)
6-
faraday (2.7.11)
7-
base64
8-
faraday-net_http (>= 2.0, < 3.1)
9-
ruby2_keywords (>= 0.0.4)
7+
ethon (0.16.0)
8+
ffi (>= 1.15.0)
9+
event_stream_parser (1.0.0)
10+
faraday (2.9.2)
11+
faraday-net_http (>= 2.0, < 3.2)
1012
faraday-multipart (1.0.4)
1113
multipart-post (~> 2)
1214
faraday-net_http (3.0.2)
13-
google-protobuf (3.25.0-arm64-darwin)
14-
googleapis-common-protos-types (1.9.0)
15-
google-protobuf (~> 3.18)
15+
faraday-typhoeus (1.1.0)
16+
faraday (~> 2.0)
17+
typhoeus (~> 1.4)
18+
ffi (1.17.0-arm64-darwin)
19+
gemini-ai (4.1.0)
20+
event_stream_parser (~> 1.0)
21+
faraday (~> 2.9, >= 2.9.2)
22+
faraday-typhoeus (~> 1.1)
23+
googleauth (~> 1.8)
24+
typhoeus (~> 1.4, >= 1.4.1)
25+
google-cloud-env (2.1.1)
26+
faraday (>= 1.0, < 3.a)
27+
google-protobuf (3.25.3-arm64-darwin)
28+
googleapis-common-protos-types (1.15.0)
29+
google-protobuf (>= 3.18, < 5.a)
30+
googleauth (1.11.0)
31+
faraday (>= 1.0, < 3.a)
32+
google-cloud-env (~> 2.1)
33+
jwt (>= 1.4, < 3.0)
34+
multi_json (~> 1.11)
35+
os (>= 0.9, < 2.0)
36+
signet (>= 0.16, < 2.a)
37+
jwt (2.8.2)
38+
base64
39+
multi_json (1.15.0)
1640
multipart-post (2.3.0)
17-
opentelemetry-api (1.2.3)
18-
opentelemetry-common (0.20.0)
41+
opentelemetry-api (1.2.5)
42+
opentelemetry-common (0.21.0)
1943
opentelemetry-api (~> 1.0)
20-
opentelemetry-exporter-otlp (0.26.1)
44+
opentelemetry-exporter-otlp (0.26.3)
2145
google-protobuf (~> 3.14)
2246
googleapis-common-protos-types (~> 1.3)
2347
opentelemetry-api (~> 1.1)
2448
opentelemetry-common (~> 0.20)
2549
opentelemetry-sdk (~> 1.2)
2650
opentelemetry-semantic_conventions
27-
opentelemetry-registry (0.3.0)
51+
opentelemetry-registry (0.3.1)
2852
opentelemetry-api (~> 1.1)
29-
opentelemetry-sdk (1.3.1)
53+
opentelemetry-sdk (1.3.2)
3054
opentelemetry-api (~> 1.1)
3155
opentelemetry-common (~> 0.20)
3256
opentelemetry-registry (~> 0.2)
@@ -35,20 +59,29 @@ GEM
3559
opentelemetry-api (~> 1.0)
3660
opentelemetry-semantic_conventions_ai (0.0.3)
3761
opentelemetry-api (~> 1.0)
38-
ruby-openai (5.2.0)
39-
event_stream_parser (>= 0.3.0, < 1.0.0)
62+
os (1.1.4)
63+
public_suffix (6.0.0)
64+
ruby-openai (7.1.0)
65+
event_stream_parser (>= 0.3.0, < 2.0.0)
4066
faraday (>= 1)
4167
faraday-multipart (>= 1)
42-
ruby2_keywords (0.0.5)
43-
traceloop-sdk (0.0.1)
68+
signet (0.19.0)
69+
addressable (~> 2.8)
70+
faraday (>= 0.17.5, < 3.a)
71+
jwt (>= 1.5, < 3.0)
72+
multi_json (~> 1.10)
73+
traceloop-sdk (0.0.5)
4474
opentelemetry-exporter-otlp (~> 0.26.1)
4575
opentelemetry-sdk (~> 1.3.1)
4676
opentelemetry-semantic_conventions_ai (~> 0.0.3)
77+
typhoeus (1.4.1)
78+
ethon (>= 0.9.0)
4779

4880
PLATFORMS
4981
arm64-darwin-23
5082

5183
DEPENDENCIES
84+
gemini-ai (~> 4.1)
5285
ruby-openai
5386
traceloop-sdk
5487

sample-app/gemini.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require 'gemini-ai'
2+
require "traceloop/sdk"
3+
4+
client = Gemini.new(
5+
credentials: {
6+
service: 'vertex-ai-api',
7+
region: 'us-east4'
8+
},
9+
options: { model: 'gemini-pro', server_sent_events: true }
10+
)
11+
12+
traceloop = Traceloop::SDK::Traceloop.new
13+
14+
traceloop.llm_call(provider="vertexai", model="gemini-pro") do |tracer|
15+
tracer.log_prompt(user_prompt="Tell me a joke about OpenTelemetry")
16+
response = client.generate_content(
17+
{ contents: { role: "user", parts: { text: "Tell me a joke about OpenTelemetry" } } })
18+
tracer.log_response(response)
19+
puts response.dig("candidates", 0, "content")
20+
end

sample-app/openai.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
traceloop = Traceloop::SDK::Traceloop.new
1111

12-
traceloop.llm_call() do |tracer|
13-
tracer.log_prompt(model="gpt-3.5-turbo", user_prompt="Tell me a joke about OpenTelemetry")
12+
traceloop.llm_call(provider="openai", model="gpt-3.5-turbo") do |tracer|
13+
tracer.log_prompt(user_prompt="Tell me a joke about OpenTelemetry")
1414
response = client.chat(
1515
parameters: {
1616
model: "gpt-3.5-turbo",

traceloop-sdk/lib/traceloop/sdk.rb

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,50 @@ def initialize
2323
end
2424

2525
class Tracer
26-
def initialize(span)
26+
def initialize(span, provider, model)
2727
@span = span
28+
@provider = provider
29+
@model = model
2830
end
2931

30-
def log_prompt(model, system_prompt="", user_prompt)
32+
def log_prompt(system_prompt="", user_prompt)
33+
unless system_prompt.empty?
34+
@span.add_attributes({
35+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.role" => "system",
36+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.content" => system_prompt,
37+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.1.role" => "user",
38+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.1.content" => user_prompt
39+
})
40+
else
41+
@span.add_attributes({
42+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.role" => "user",
43+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.content" => user_prompt
44+
})
45+
end
46+
end
47+
48+
def log_response(response)
49+
# This is Gemini specific, see -
50+
# https://github.com/gbaptista/gemini-ai?tab=readme-ov-file#generate_content
51+
if response.has_key?("candidates")
52+
log_gemini_response(response)
53+
else
54+
log_openai_response(response)
55+
end
56+
end
57+
58+
def log_gemini_response(response)
3159
@span.add_attributes({
32-
OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_REQUEST_MODEL => model,
33-
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.role" => "system",
34-
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.0.content" => system_prompt,
35-
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.1.role" => "user",
36-
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_PROMPTS}.1.content" => user_prompt
60+
OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_RESPONSE_MODEL => @model,
3761
})
62+
63+
@span.add_attributes({
64+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_COMPLETIONS}.0.role" => "assistant",
65+
"#{OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_COMPLETIONS}.0.content" => response.dig("candidates", 0, "content", "parts", 0, "text")
66+
})
3867
end
3968

40-
def log_response(response)
69+
def log_openai_response(response)
4170
@span.add_attributes({
4271
OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_RESPONSE_MODEL => response.dig("model"),
4372
})
@@ -57,9 +86,12 @@ def log_response(response)
5786
end
5887
end
5988

60-
def llm_call
61-
@tracer.in_span("openai.chat") do |span|
62-
yield Tracer.new(span)
89+
def llm_call(provider, model)
90+
@tracer.in_span("#{provider}.chat") do |span|
91+
span.add_attributes({
92+
OpenTelemetry::SemanticConventionsAi::SpanAttributes::LLM_REQUEST_MODEL => model,
93+
})
94+
yield Tracer.new(span, provider, model)
6395
end
6496
end
6597
end

traceloop-sdk/traceloop-sdk.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |spec|
22
spec.name = 'traceloop-sdk'
3-
spec.version = '0.0.2'
3+
spec.version = '0.0.5'
44
spec.authors = ["Traceloop"]
55
spec.email = ['dev@traceloop.com']
66

0 commit comments

Comments
 (0)