llm_gateway 0.5.0 → 0.6.0
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 +26 -0
- data/README.md +95 -42
- data/docs/migration_guide_0.6.0.md +386 -0
- data/lib/llm_gateway/adapters/adapter.rb +7 -10
- data/lib/llm_gateway/adapters/anthropic/stream_mapper.rb +33 -6
- data/lib/llm_gateway/adapters/normalized_stream_accumulator.rb +87 -26
- data/lib/llm_gateway/adapters/openai/chat_completions/stream_mapper.rb +40 -16
- data/lib/llm_gateway/adapters/openai/responses/stream_mapper.rb +42 -21
- data/lib/llm_gateway/adapters/stream_mapper.rb +9 -2
- data/lib/llm_gateway/adapters/structs.rb +102 -52
- data/lib/llm_gateway/base_client.rb +2 -4
- data/lib/llm_gateway/clients/anthropic.rb +5 -4
- data/lib/llm_gateway/clients/groq.rb +8 -6
- data/lib/llm_gateway/clients/openai.rb +20 -18
- data/lib/llm_gateway/prompt.rb +35 -17
- data/lib/llm_gateway/version.rb +1 -1
- data/lib/llm_gateway.rb +3 -21
- metadata +3 -2
|
@@ -6,18 +6,20 @@ module LlmGateway
|
|
|
6
6
|
module Clients
|
|
7
7
|
class OpenAI < BaseClient
|
|
8
8
|
CODEX_BASE_ENDPOINT = "https://chatgpt.com/backend-api/codex"
|
|
9
|
+
DEFAULT_MODEL = "gpt-4o"
|
|
10
|
+
DEFAULT_EMBEDDINGS_MODEL = "text-embedding-3-small"
|
|
9
11
|
|
|
10
12
|
attr_reader :account_id
|
|
11
13
|
|
|
12
|
-
def initialize(
|
|
14
|
+
def initialize(api_key: ENV["OPENAI_API_KEY"], account_id: nil)
|
|
13
15
|
@base_endpoint = "https://api.openai.com/v1"
|
|
14
16
|
@account_id = account_id
|
|
15
|
-
super(
|
|
17
|
+
super(api_key: api_key)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
def chat(messages, tools: nil, system: [], **options)
|
|
20
|
+
def chat(messages, tools: nil, system: [], model: DEFAULT_MODEL, **options)
|
|
19
21
|
body = {
|
|
20
|
-
model:
|
|
22
|
+
model: model,
|
|
21
23
|
messages: system + messages
|
|
22
24
|
}
|
|
23
25
|
body[:tools] = tools if tools
|
|
@@ -26,9 +28,9 @@ module LlmGateway
|
|
|
26
28
|
post("chat/completions", body)
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
def stream(messages, tools: nil, system: [], **options, &block)
|
|
31
|
+
def stream(messages, tools: nil, system: [], model: DEFAULT_MODEL, **options, &block)
|
|
30
32
|
body = {
|
|
31
|
-
model:
|
|
33
|
+
model: model,
|
|
32
34
|
messages: system + messages
|
|
33
35
|
}
|
|
34
36
|
body[:tools] = tools if tools
|
|
@@ -38,9 +40,9 @@ module LlmGateway
|
|
|
38
40
|
post_stream("chat/completions", body, &block)
|
|
39
41
|
end
|
|
40
42
|
|
|
41
|
-
def responses(messages, tools: nil, system: [], **options)
|
|
43
|
+
def responses(messages, tools: nil, system: [], model: DEFAULT_MODEL, **options)
|
|
42
44
|
body = {
|
|
43
|
-
model:
|
|
45
|
+
model: model,
|
|
44
46
|
input: messages.flatten
|
|
45
47
|
}
|
|
46
48
|
body[:instructions] = system[0][:content] if system.any?
|
|
@@ -50,9 +52,9 @@ module LlmGateway
|
|
|
50
52
|
post("responses", body)
|
|
51
53
|
end
|
|
52
54
|
|
|
53
|
-
def stream_responses(messages, tools: nil, system: [], **options, &block)
|
|
55
|
+
def stream_responses(messages, tools: nil, system: [], model: DEFAULT_MODEL, **options, &block)
|
|
54
56
|
body = {
|
|
55
|
-
model:
|
|
57
|
+
model: model,
|
|
56
58
|
input: messages.flatten
|
|
57
59
|
}
|
|
58
60
|
body[:instructions] = system[0][:content] if system.any?
|
|
@@ -74,8 +76,8 @@ module LlmGateway
|
|
|
74
76
|
token_manager.access_token
|
|
75
77
|
end
|
|
76
78
|
|
|
77
|
-
def chat_codex(messages, tools: nil, system: [], account_id: nil, **options)
|
|
78
|
-
body = build_codex_body(messages, system, tools, **options)
|
|
79
|
+
def chat_codex(messages, tools: nil, system: [], account_id: nil, model: DEFAULT_MODEL, **options)
|
|
80
|
+
body = build_codex_body(messages, system, tools, model: model, **options)
|
|
79
81
|
|
|
80
82
|
completed_response = nil
|
|
81
83
|
post_codex_stream("responses", body, account_id: account_id) do |raw_sse|
|
|
@@ -87,8 +89,8 @@ module LlmGateway
|
|
|
87
89
|
completed_response
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
def stream_codex(messages, tools: nil, system: [], account_id: nil, **options, &block)
|
|
91
|
-
body = build_codex_body(messages, system, tools, **options)
|
|
92
|
+
def stream_codex(messages, tools: nil, system: [], account_id: nil, model: DEFAULT_MODEL, **options, &block)
|
|
93
|
+
body = build_codex_body(messages, system, tools, model: model, **options)
|
|
92
94
|
post_codex_stream("responses", body, account_id: account_id, &block)
|
|
93
95
|
end
|
|
94
96
|
|
|
@@ -96,10 +98,10 @@ module LlmGateway
|
|
|
96
98
|
get("files/#{file_id}/content")
|
|
97
99
|
end
|
|
98
100
|
|
|
99
|
-
def generate_embeddings(input)
|
|
101
|
+
def generate_embeddings(input, model: DEFAULT_EMBEDDINGS_MODEL)
|
|
100
102
|
body = {
|
|
101
103
|
input:,
|
|
102
|
-
model:
|
|
104
|
+
model: model
|
|
103
105
|
}
|
|
104
106
|
post("embeddings", body)
|
|
105
107
|
end
|
|
@@ -110,12 +112,12 @@ module LlmGateway
|
|
|
110
112
|
|
|
111
113
|
private
|
|
112
114
|
|
|
113
|
-
def build_codex_body(messages, system, tools, **options)
|
|
115
|
+
def build_codex_body(messages, system, tools, model:, **options)
|
|
114
116
|
instructions = Array(system).filter_map { |s| s.is_a?(Hash) ? s[:content] : s }.join("\n")
|
|
115
117
|
instructions = "You are a helpful assistant." if instructions.empty?
|
|
116
118
|
|
|
117
119
|
body = {
|
|
118
|
-
model:
|
|
120
|
+
model: model,
|
|
119
121
|
instructions: instructions,
|
|
120
122
|
input: messages,
|
|
121
123
|
store: false,
|
data/lib/llm_gateway/prompt.rb
CHANGED
|
@@ -2,7 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module LlmGateway
|
|
4
4
|
class Prompt
|
|
5
|
-
|
|
5
|
+
UNSET = Object.new.freeze
|
|
6
|
+
|
|
7
|
+
attr_reader :provider, :model
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def provider(value = UNSET)
|
|
11
|
+
@provider = value unless value.equal?(UNSET)
|
|
12
|
+
@provider
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def provider=(value)
|
|
16
|
+
@provider = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def model(value = UNSET)
|
|
20
|
+
@model = value unless value.equal?(UNSET)
|
|
21
|
+
@model
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def model=(value)
|
|
25
|
+
@model = value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
6
28
|
|
|
7
29
|
def self.before_execute(*methods, &block)
|
|
8
30
|
before_execute_callbacks.concat(methods)
|
|
@@ -26,23 +48,19 @@ module LlmGateway
|
|
|
26
48
|
super
|
|
27
49
|
subclass.instance_variable_set(:@before_execute_callbacks, before_execute_callbacks.dup)
|
|
28
50
|
subclass.instance_variable_set(:@after_execute_callbacks, after_execute_callbacks.dup)
|
|
51
|
+
subclass.provider = provider
|
|
52
|
+
subclass.model = model
|
|
29
53
|
end
|
|
30
54
|
|
|
31
|
-
def initialize(model)
|
|
32
|
-
@
|
|
33
|
-
@
|
|
34
|
-
LlmGateway.configured_clients.values.find do |client|
|
|
35
|
-
client.client.model_key == model
|
|
36
|
-
end
|
|
37
|
-
else
|
|
38
|
-
model
|
|
39
|
-
end
|
|
55
|
+
def initialize(provider = nil, model = nil)
|
|
56
|
+
@provider = provider || self.class.provider
|
|
57
|
+
@model = model || self.class.model
|
|
40
58
|
end
|
|
41
59
|
|
|
42
60
|
def run
|
|
43
61
|
run_callbacks(:before_execute, prompt)
|
|
44
62
|
|
|
45
|
-
response =
|
|
63
|
+
response = stream
|
|
46
64
|
|
|
47
65
|
response_content = if respond_to?(:extract_response)
|
|
48
66
|
extract_response(response)
|
|
@@ -61,12 +79,12 @@ module LlmGateway
|
|
|
61
79
|
result
|
|
62
80
|
end
|
|
63
81
|
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
82
|
+
def stream(provider: nil, model: nil, **options)
|
|
83
|
+
stream_provider = provider || self.provider
|
|
84
|
+
stream_model = model || self.model
|
|
85
|
+
options[:model] = stream_model if stream_model
|
|
86
|
+
|
|
87
|
+
stream_provider.stream(prompt, tools: tools, system: system_prompt, **options)
|
|
70
88
|
end
|
|
71
89
|
|
|
72
90
|
def tools
|
data/lib/llm_gateway/version.rb
CHANGED
data/lib/llm_gateway.rb
CHANGED
|
@@ -100,6 +100,9 @@ module LlmGateway
|
|
|
100
100
|
def self.build_provider(config)
|
|
101
101
|
config = config.transform_keys(&:to_sym)
|
|
102
102
|
provider_name = config.delete(:provider)
|
|
103
|
+
if config.key?(:model_key)
|
|
104
|
+
raise ArgumentError, "model_key is no longer a provider option; pass model: to chat/stream instead"
|
|
105
|
+
end
|
|
103
106
|
entry = ProviderRegistry.resolve(provider_name)
|
|
104
107
|
|
|
105
108
|
client = entry[:client].new(**config)
|
|
@@ -153,25 +156,4 @@ module LlmGateway
|
|
|
153
156
|
ProviderRegistry.register("openai_codex",
|
|
154
157
|
client: Clients::OpenAI,
|
|
155
158
|
adapter: Adapters::OpenAICodex::ResponsesAdapter)
|
|
156
|
-
|
|
157
|
-
# Backward-compatible aliases (deprecated)
|
|
158
|
-
ProviderRegistry.register("anthropic_apikey_messages",
|
|
159
|
-
client: Clients::Anthropic,
|
|
160
|
-
adapter: Adapters::Anthropic::MessagesAdapter)
|
|
161
|
-
|
|
162
|
-
ProviderRegistry.register("openai_apikey_completions",
|
|
163
|
-
client: Clients::OpenAI,
|
|
164
|
-
adapter: Adapters::OpenAI::ChatCompletionsAdapter)
|
|
165
|
-
|
|
166
|
-
ProviderRegistry.register("openai_apikey_responses",
|
|
167
|
-
client: Clients::OpenAI,
|
|
168
|
-
adapter: Adapters::OpenAI::ResponsesAdapter)
|
|
169
|
-
|
|
170
|
-
ProviderRegistry.register("groq_apikey_completions",
|
|
171
|
-
client: Clients::Groq,
|
|
172
|
-
adapter: Adapters::Groq::ChatCompletionsAdapter)
|
|
173
|
-
|
|
174
|
-
ProviderRegistry.register("openai_oauth_codex",
|
|
175
|
-
client: Clients::OpenAI,
|
|
176
|
-
adapter: Adapters::OpenAICodex::ResponsesAdapter)
|
|
177
159
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llm_gateway
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- billybonks
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dry-struct
|
|
@@ -42,6 +42,7 @@ files:
|
|
|
42
42
|
- README.md
|
|
43
43
|
- Rakefile
|
|
44
44
|
- docs/migration-guide.md
|
|
45
|
+
- docs/migration_guide_0.6.0.md
|
|
45
46
|
- lib/llm_gateway.rb
|
|
46
47
|
- lib/llm_gateway/adapters/adapter.rb
|
|
47
48
|
- lib/llm_gateway/adapters/anthropic/acts_like_messages.rb
|