diff --git a/pkgs-set/pkgs/cliproxy-responses-done.patch b/pkgs-set/pkgs/cliproxy-responses-done.patch new file mode 100644 --- /dev/null +++ b/pkgs-set/pkgs/cliproxy-responses-done.patch @@ -0,0 +1,49 @@ +diff --git a/internal/translator/gemini/openai/responses/gemini_openai-responses_response.go b/internal/translator/gemini/openai/responses/gemini_openai-responses_response.go +index 36d30df..fd9edd7 100644 +--- a/internal/translator/gemini/openai/responses/gemini_openai-responses_response.go ++++ b/internal/translator/gemini/openai/responses/gemini_openai-responses_response.go +@@ -19,6 +19,7 @@ type geminiToResponsesState struct { + ResponseID string + CreatedAt int64 + Started bool ++ Completed bool + + // message aggregation + MsgOpened bool +@@ -100,6 +101,9 @@ func ConvertGeminiResponseToOpenAIResponses(_ context.Context, modelName string, + } + } + st := (*param).(*geminiToResponsesState) ++ if st.Completed { ++ return [][]byte{} ++ } + if st.FuncArgsBuf == nil { + st.FuncArgsBuf = make(map[int]*strings.Builder) + } +@@ -121,9 +125,17 @@ func ConvertGeminiResponseToOpenAIResponses(_ context.Context, modelName string, + } + + rawJSON = bytes.TrimSpace(rawJSON) +- if len(rawJSON) == 0 || bytes.Equal(rawJSON, []byte("[DONE]")) { ++ if len(rawJSON) == 0 { + return [][]byte{} + } ++ if bytes.Equal(rawJSON, []byte("[DONE]")) { ++ if !st.Started { ++ return [][]byte{} ++ } ++ // Some Gemini streaming routes terminate with [DONE] without sending ++ // a final candidate chunk. Reuse the normal STOP finalization path. ++ rawJSON = []byte(`{"candidates":[{"finishReason":"STOP"}]}`) ++ } + + root := gjson.ParseBytes(rawJSON) + if !root.Exists() { +@@ -562,6 +574,7 @@ func ConvertGeminiResponseToOpenAIResponses(_ context.Context, modelName string, + } + + out = append(out, emitEvent("response.completed", completed)) ++ st.Completed = true + } + + return out diff --git a/pkgs-set/pkgs/cliproxyapi.nix b/pkgs-set/pkgs/cliproxyapi.nix --- a/pkgs-set/pkgs/cliproxyapi.nix +++ b/pkgs-set/pkgs/cliproxyapi.nix @@ -1,26 +1,25 @@ { - stdenvNoCC, - fetchurl, - autoPatchelfHook, + buildGoModule, + fetchFromGitHub, + lib, ... }: -stdenvNoCC.mkDerivation { +buildGoModule { pname = "cliproxyapi"; - version = "7.2.97"; + version = "7.2.97-patched"; - src = fetchurl { - url = "https://github.com/router-for-me/CLIProxyAPI/releases/download/v7.2.97/CLIProxyAPI_7.2.97_linux_amd64.tar.gz"; - hash = "sha256-nefXh2m9WqKJAe8YdmxlxB/bdQJYpbMYES3gKSgBbtQ="; + src = fetchFromGitHub { + owner = "router-for-me"; + repo = "CLIProxyAPI"; + rev = "42f36b94e0805a9897c3aa3be46a2b124be0057e"; + hash = "sha256-Jpcz3wjhXWQJuDpJkhLU4HfDIBRebv921NOle3YvSTo="; }; - nativeBuildInputs = [ autoPatchelfHook ]; + patches = [ ./cliproxy-responses-done.patch ]; + vendorHash = "sha256-OKZQ+Lyt3nwUhJMNE3zmwXN9vEl9Hx4W/CrzAhHfBTg="; + subPackages = [ "cmd/server" ]; + ldflags = [ "-s" "-w" "-X main.Version=7.2.97-patched" ]; - dontUnpack = true; - - installPhase = '' - tar -xzf "$src" - install -Dm755 cli-proxy-api $out/bin/cli-proxy-api - install -Dm644 LICENSE $out/share/licenses/cliproxyapi/LICENSE - ''; + postInstall = "mv $out/bin/server $out/bin/cli-proxy-api"; }