Skip to content

Commit f8aa102

Browse files
authored
Merge pull request #20 from emilrueh/dev
Coroutine based non-blocking async requests via copas
2 parents 7fa9c65 + aab6426 commit f8aa102

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

rockspecs/lua-genai-0.3-1.rockspec

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package = "lua-genai"
2+
version = "0.3-1"
3+
source = {
4+
url = "https://github.com/emilrueh/lua-genai/archive/refs/tags/v0.3.tar.gz"
5+
}
6+
description = {
7+
summary = "Generative AI SDK",
8+
detailed = "Interface for generative AI providers like OpenAI, Anthropic, Google Gemini, DeepSeek, etc. abstracting away provider-specific payload structures and response parsing to simplify switching models with optional async requests.",
9+
homepage = "https://github.com/emilrueh/lua-genai",
10+
license = "Zlib"
11+
}
12+
dependencies = {
13+
"lua >= 5.1",
14+
"lua-cjson",
15+
"luasec"
16+
}
17+
build = {
18+
type = "builtin",
19+
modules = {
20+
genai = "src/genai/init.lua",
21+
["genai.features"] = "src/genai/features/init.lua",
22+
["genai.features.chat"] = "src/genai/features/chat.lua",
23+
["genai.genai"] = "src/genai/genai.lua",
24+
["genai.providers"] = "src/genai/providers/init.lua",
25+
["genai.providers.anthropic"] = "src/genai/providers/anthropic.lua",
26+
["genai.providers.openai"] = "src/genai/providers/openai.lua",
27+
["genai.utils"] = "src/genai/utils.lua"
28+
}
29+
}

src/genai/genai.lua

+6-3
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@ end
6767
---@return table payload
6868
---@return function? callback Streaming handler
6969
---@return table? accumulator Schema storing full streamed response
70+
---@return boolean async Whether to use non-blocking https via copas
7071
function GenAI:_prepare_response_requirements(opts)
7172
local headers = self.provider.construct_headers(self._api_key)
7273
local payload = self.provider.construct_payload(opts)
7374
local accumulator, callback = self:_setup_stream(opts.settings.stream)
74-
return headers, payload, callback, accumulator
75+
local async = opts.settings and opts.settings.async or false
76+
return headers, payload, callback, accumulator, async
7577
end
7678

7779
---Execute API call to specified GenAI model with all payload and settings
@@ -80,15 +82,16 @@ end
8082
---@return number input_tokens
8183
---@return number output_tokens
8284
function GenAI:call(opts)
83-
local headers, payload, callback, accumulator = self:_prepare_response_requirements(opts)
85+
local headers, payload, callback, accumulator, async = self:_prepare_response_requirements(opts)
8486

8587
local response = utils.send_request(
8688
self._endpoint,
8789
cjson.encode(payload),
8890
"POST",
8991
headers,
9092
callback,
91-
self.provider.handle_exceptions
93+
self.provider.handle_exceptions,
94+
async
9295
)
9396

9497
local reply, input_tokens, output_tokens =

src/genai/utils.lua

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
local cjson = require("cjson")
2-
local https = require("ssl.https")
2+
local copas = require("copas")
3+
local ssl_https = require("ssl.https")
34
local ltn12 = require("ltn12")
45

56
---@module "genai.utils"
67
local utils = {}
78

8-
---Https request with partial response functionality via callback
9+
---Decides to either call https request via non-blocking copas or blocking ssl
10+
---@param opts table
11+
---@return number response
12+
---@return number status
13+
---@return table headers
14+
local function _exec_request(opts, async)
15+
if async then return copas.http.request(opts) end
16+
return ssl_https.request(opts)
17+
end
18+
19+
---Https request with partial response functionality via callback as well as non-blocking via copas
920
---@param url string
1021
---@param payload table?
1122
---@param method string?
1223
---@param headers table?
1324
---@param callback function?
1425
---@param exception_handler function?
1526
---@return string|table body
16-
function utils.send_request(url, payload, method, headers, callback, exception_handler)
27+
function utils.send_request(url, payload, method, headers, callback, exception_handler, async)
1728
local response_body = {}
1829
local final_sink = ltn12.sink.table(response_body)
1930

@@ -35,7 +46,7 @@ function utils.send_request(url, payload, method, headers, callback, exception_h
3546
source = payload and ltn12.source.string(payload) or nil,
3647
}
3748

38-
local _, status_code, response_headers = https.request(request_opts)
49+
local _, status_code, response_headers = _exec_request(request_opts, async)
3950
local body = table.concat(response_body)
4051

4152
-- decode body if json response

0 commit comments

Comments
 (0)