Commit 622864f

mo khan <mo@mokhan.ca>
2025-08-16 19:36:53
refactor: api http connection and host parsing
1 parent c128bb9
Changed files (2)
lib/elelem/api.rb
@@ -2,33 +2,67 @@
 
 module Elelem
   class Api
-    attr_reader :configuration
+    attr_reader :configuration, :uri
 
     def initialize(configuration)
       @configuration = configuration
+      @uri = build_uri(configuration.host)
     end
 
     def chat(messages, &block)
-      body = {
+      Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
+        http.read_timeout = 3_600
+        http.open_timeout = 10
+
+        http.request(build_request(messages)) do |response|
+          if response.is_a?(Net::HTTPSuccess)
+            response.read_body(&block)
+          else
+            configuration.logger.error(response.inspect)
+          end
+        end
+      end
+    end
+
+    private
+
+    def build_uri(raw_host)
+      if raw_host =~ %r{^https?://}
+        host = raw_host
+      else
+        # No scheme โ€“ decide which one to add.
+        # * localhost or 127.0.0.1 โ†’ http
+        # * anything else          โ†’ https
+        if raw_host.start_with?('localhost', '127.0.0.1')
+          scheme = 'http://'
+        else
+          scheme = 'https://'
+        end
+        host = scheme + raw_host
+      end
+
+      endpoint = "#{host.sub(%r{/?$}, '')}/api/chat"
+      URI(endpoint)
+    end
+
+    def build_request(messages)
+      Net::HTTP::Post.new(uri).tap do |request|
+        request["Content-Type"] = "application/json"
+        request["Authorization"] = "Bearer #{configuration.token}" if configuration.token && !configuration.token.empty?
+        request.body = build_payload(messages).to_json
+      end
+    end
+
+    def build_payload(messages)
+      {
         messages: messages,
         model: configuration.model,
         stream: true,
         keep_alive: "5m",
         options: { temperature: 0.1 },
         tools: configuration.tools.to_h
-      }
-      configuration.logger.debug(JSON.pretty_generate(body))
-      json_body = body.to_json
-
-      req = Net::HTTP::Post.new(configuration.uri)
-      req["Content-Type"] = "application/json"
-      req.body = json_body
-      req["Authorization"] = "Bearer #{configuration.token}" if configuration.token
-
-      configuration.http.request(req) do |response|
-        raise response.inspect unless response.code == "200"
-
-        response.read_body(&block)
+      }.tap do |payload|
+        configuration.logger.debug(JSON.pretty_generate(payload))
       end
     end
   end
lib/elelem/configuration.rb
@@ -11,13 +11,6 @@ module Elelem
       @debug = debug
     end
 
-    def http
-      @http ||= Net::HTTP.new(uri.host, uri.port).tap do |h|
-        h.read_timeout = 3_600
-        h.open_timeout = 10
-      end
-    end
-
     def tui
       @tui ||= TUI.new($stdin, $stdout)
     end
@@ -32,10 +25,6 @@ module Elelem
       end
     end
 
-    def uri
-      @uri ||= URI("#{scheme}://#{host}/api/chat")
-    end
-
     def conversation
       @conversation ||= Conversation.new.tap do |conversation|
         resources = mcp_clients.map do |client|
@@ -57,10 +46,6 @@ module Elelem
 
     private
 
-    def scheme
-      host.match?(/\A(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?\z/) ? "http" : "https"
-    end
-
     def mcp_tools
       @mcp_tools ||= mcp_clients.map do |client|
         client.tools.map do |tool|