ticuna 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/lib/ticuna/llm.rb +5 -5
- data/lib/ticuna/providers/openai.rb +9 -2
- data/lib/ticuna/providers.rb +4 -0
- data/lib/ticuna/response.rb +38 -4
- data/lib/ticuna/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55e07fd5840706e2936718a07ad6e6e6be5ae8681b6c8b763bac6c9c073d632f
|
|
4
|
+
data.tar.gz: '0118e2253d49b82acbbe08ed17145997330a9c42f30f276e87b7ff01136710d9'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 90467485b1691fdf24b14c442945f82f8b58db85b4ff47ee1f2403adf96b3fdd5efcd54fc94cd3c88068151037ac220058536797c9b407f2acd83b2a7edbab3e
|
|
7
|
+
data.tar.gz: d60b05c8b3e1306835c9996e91b88accfe8ca2fe7d1f47c0358d7ae2903a4c7b2bc2e6949007c6294cda3a312c9c5bbea81f9d9cc40095d830eea04c8c657031
|
data/CHANGELOG.md
CHANGED
|
@@ -31,4 +31,8 @@
|
|
|
31
31
|
- Add `errors?` method
|
|
32
32
|
|
|
33
33
|
## [0.2.6] - 2025-10-22
|
|
34
|
-
- Add `context` method
|
|
34
|
+
- Add `context` method
|
|
35
|
+
|
|
36
|
+
## [0.2.7] - 2025-10-22
|
|
37
|
+
- Add modular response, to attend any LLM model
|
|
38
|
+
- Add `.response` method in Ticuna::Response to ease access to the real response
|
data/lib/ticuna/llm.rb
CHANGED
|
@@ -10,12 +10,11 @@ module Ticuna
|
|
|
10
10
|
def self.new(provider = nil)
|
|
11
11
|
provider_key = detect_provider(provider)
|
|
12
12
|
provider_client = Ticuna::Providers::CLIENTS[provider_key].call
|
|
13
|
-
|
|
14
|
-
new_instance.send(:initialize_llm, provider_client)
|
|
15
|
-
new_instance
|
|
13
|
+
allocate.tap { |instance| instance.send(:initialize_llm, provider_key, provider_client) }
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
def initialize_llm(provider_client)
|
|
16
|
+
def initialize_llm(provider_key, provider_client)
|
|
17
|
+
@provider_key = provider_key
|
|
19
18
|
@provider = provider_client
|
|
20
19
|
@tools = []
|
|
21
20
|
@contexts = []
|
|
@@ -52,7 +51,8 @@ module Ticuna
|
|
|
52
51
|
model_string = detect_llm_model(model)
|
|
53
52
|
|
|
54
53
|
Ticuna::Response.new(
|
|
55
|
-
@provider.ask_with_messages(messages, stream: stream, model: model_string, output_format: output_format, &block)
|
|
54
|
+
@provider.ask_with_messages(messages, stream: stream, model: model_string, output_format: output_format, &block),
|
|
55
|
+
provider: @provider_key
|
|
56
56
|
)
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -7,6 +7,8 @@ module Ticuna
|
|
|
7
7
|
class OpenAI < BaseProvider
|
|
8
8
|
def initialize(api_key:)
|
|
9
9
|
super(api_key: api_key, base_url: "https://api.openai.com/v1/")
|
|
10
|
+
@response = String.new
|
|
11
|
+
@raw_response = String.new
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def ask(message, stream: false, model: "gpt-4.1-nano", output_format: :text, &block)
|
|
@@ -67,7 +69,8 @@ module Ticuna
|
|
|
67
69
|
end
|
|
68
70
|
end
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
@response = full_text
|
|
73
|
+
@raw_response = {
|
|
71
74
|
"id" => "streamed_completion_#{Time.now.to_i}",
|
|
72
75
|
"object" => "chat.completion",
|
|
73
76
|
"model" => body[:model],
|
|
@@ -81,9 +84,13 @@ module Ticuna
|
|
|
81
84
|
}
|
|
82
85
|
else
|
|
83
86
|
resp = @connection.post(path, body.to_json)
|
|
84
|
-
JSON.parse(resp.body)
|
|
87
|
+
@raw_response = JSON.parse(resp.body)
|
|
88
|
+
@response = @raw_response.dig("choices", 0, "message", "content")
|
|
85
89
|
end
|
|
90
|
+
|
|
91
|
+
@raw_response
|
|
86
92
|
end
|
|
93
|
+
attr_reader :response, :raw_response
|
|
87
94
|
end
|
|
88
95
|
end
|
|
89
96
|
end
|
data/lib/ticuna/providers.rb
CHANGED
|
@@ -24,5 +24,9 @@ module Ticuna
|
|
|
24
24
|
# deepseek: -> { Ticuna::Providers::DeepSeek.new(api_key: ENVS[:deepseek].call) },
|
|
25
25
|
# mistral: -> { Ticuna::Providers::Mistral.new(api_key: ENVS[:mistral].call) }
|
|
26
26
|
}.freeze
|
|
27
|
+
|
|
28
|
+
RESPONSE_EXTRACTORS = {
|
|
29
|
+
openai: ->(data) { data.dig(:choices, 0, :message, :content) }
|
|
30
|
+
}.freeze
|
|
27
31
|
end
|
|
28
32
|
end
|
data/lib/ticuna/response.rb
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "ticuna/providers"
|
|
4
5
|
|
|
5
6
|
module Ticuna
|
|
6
7
|
class Response
|
|
7
|
-
attr_reader :data, :errors, :parsed
|
|
8
|
+
attr_reader :data, :errors, :parsed, :raw_response, :response, :provider
|
|
8
9
|
|
|
9
|
-
def initialize(raw)
|
|
10
|
+
def initialize(raw, provider: nil)
|
|
11
|
+
@provider = provider
|
|
12
|
+
@raw_response = raw
|
|
10
13
|
@parsed =
|
|
11
14
|
case raw
|
|
12
15
|
when String
|
|
@@ -22,7 +25,14 @@ module Ticuna
|
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
@data = deep_symbolize_keys(@parsed)
|
|
25
|
-
|
|
28
|
+
error_payload =
|
|
29
|
+
if @parsed.is_a?(Hash)
|
|
30
|
+
@parsed["error"] || @parsed[:error] || []
|
|
31
|
+
else
|
|
32
|
+
[]
|
|
33
|
+
end
|
|
34
|
+
@errors = deep_symbolize_keys(error_payload)
|
|
35
|
+
@response = resolve_response
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
def [](key)
|
|
@@ -70,12 +80,36 @@ module Ticuna
|
|
|
70
80
|
def wrap(value)
|
|
71
81
|
case value
|
|
72
82
|
when Hash
|
|
73
|
-
self.class.new(value)
|
|
83
|
+
self.class.new(value, provider: provider)
|
|
74
84
|
when Array
|
|
75
85
|
value.map { |v| wrap(v) }
|
|
76
86
|
else
|
|
77
87
|
value
|
|
78
88
|
end
|
|
79
89
|
end
|
|
90
|
+
|
|
91
|
+
def resolve_response
|
|
92
|
+
from_provider = extract_from_provider
|
|
93
|
+
return from_provider unless blank?(from_provider)
|
|
94
|
+
|
|
95
|
+
fallback =
|
|
96
|
+
if @data.is_a?(Hash)
|
|
97
|
+
@data[:content] || @data[:response]
|
|
98
|
+
end
|
|
99
|
+
return fallback unless blank?(fallback)
|
|
100
|
+
|
|
101
|
+
@parsed if @parsed.is_a?(String)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def blank?(value)
|
|
105
|
+
value.respond_to?(:empty?) ? value.empty? : !value
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def extract_from_provider
|
|
109
|
+
return unless provider
|
|
110
|
+
|
|
111
|
+
extractor = Ticuna::Providers::RESPONSE_EXTRACTORS[provider]
|
|
112
|
+
extractor&.call(@data)
|
|
113
|
+
end
|
|
80
114
|
end
|
|
81
115
|
end
|
data/lib/ticuna/version.rb
CHANGED