From f4826ccae78fc33ec733c097999c7d7bc284b801 Mon Sep 17 00:00:00 2001 From: Antar Azri Date: Wed, 20 Nov 2024 13:07:43 +0100 Subject: [PATCH 1/5] feat: add `stop_reason` to Message --- lib/llm/message.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/llm/message.rb b/lib/llm/message.rb index 9d705c3d..51aaa91a 100644 --- a/lib/llm/message.rb +++ b/lib/llm/message.rb @@ -20,6 +20,13 @@ def logprobs @extra[:logprobs] end + ## + # Returns the stop reason + # @return [String] + def stop_reason + @extra[:stop_reason] + end + def to_h {role:, content:} end From 92c01fca112e3aef10fc2bcd751f9ba602670a63 Mon Sep 17 00:00:00 2001 From: Antar Azri Date: Wed, 20 Nov 2024 13:08:10 +0100 Subject: [PATCH 2/5] feat: add `stop_reason` for OpenAI completion message --- lib/llm/providers/openai/response_parser.rb | 4 +++- spec/openai/completion_spec.rb | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/llm/providers/openai/response_parser.rb b/lib/llm/providers/openai/response_parser.rb index 87e0022e..379e27d2 100644 --- a/lib/llm/providers/openai/response_parser.rb +++ b/lib/llm/providers/openai/response_parser.rb @@ -19,7 +19,9 @@ def parse_completion(raw) { model: raw["model"], choices: raw["choices"].map do - LLM::Message.new(*_1["message"].values_at("role", "content"), {logprobs: _1["logprobs"]}) + logprobs = _1["logprobs"] + stop_reason = _1["finish_reason"] + LLM::Message.new(*_1["message"].values_at("role", "content"), {logprobs:, stop_reason:}) end, prompt_tokens: raw.dig("usage", "prompt_tokens"), completion_tokens: raw.dig("usage", "completion_tokens"), diff --git a/spec/openai/completion_spec.rb b/spec/openai/completion_spec.rb index a37269e5..1d03384c 100644 --- a/spec/openai/completion_spec.rb +++ b/spec/openai/completion_spec.rb @@ -102,6 +102,10 @@ total_tokens: 18 ) end + + it "has stop reason" do + expect(completion.choices.first.stop_reason).to eq("stop") + end end context "with an unauthorized error", :unauthorized do From c3bb081e49115ac29910550d01a8ae670938d89a Mon Sep 17 00:00:00 2001 From: Antar Azri Date: Wed, 20 Nov 2024 13:09:38 +0100 Subject: [PATCH 3/5] feat: add `stop_reason` for Anthropic completion message --- lib/llm/providers/anthropic/response_parser.rb | 3 ++- spec/anthropic/completion_spec.rb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/llm/providers/anthropic/response_parser.rb b/lib/llm/providers/anthropic/response_parser.rb index c8609597..9ae8a1a5 100644 --- a/lib/llm/providers/anthropic/response_parser.rb +++ b/lib/llm/providers/anthropic/response_parser.rb @@ -20,7 +20,8 @@ def parse_completion(raw) { model: raw["model"], choices: raw["content"].map do - LLM::Message.new(raw["role"], _1["text"]) + stop_reason = raw["stop_reason"] + LLM::Message.new(raw["role"], _1["text"], {stop_reason:}) end, prompt_tokens: raw.dig("usage", "input_tokens"), completion_tokens: raw.dig("usage", "output_tokens") diff --git a/spec/anthropic/completion_spec.rb b/spec/anthropic/completion_spec.rb index a337fad3..29d9b013 100644 --- a/spec/anthropic/completion_spec.rb +++ b/spec/anthropic/completion_spec.rb @@ -73,6 +73,10 @@ total_tokens: 2598 ) end + + it "has stop reason" do + expect(completion.choices.first.stop_reason).to eq("end_turn") + end end context "with an unauthorized error", :unauthorized do From 291662977de3f3cc7de9bc82a5805b6da16919f3 Mon Sep 17 00:00:00 2001 From: Antar Azri Date: Wed, 20 Nov 2024 13:18:56 +0100 Subject: [PATCH 4/5] feat: add `stop_reason` for Gemini completion Message --- lib/llm/providers/gemini/response_parser.rb | 4 +++- spec/gemini/completion_spec.rb | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/llm/providers/gemini/response_parser.rb b/lib/llm/providers/gemini/response_parser.rb index 653835ec..37012ae8 100644 --- a/lib/llm/providers/gemini/response_parser.rb +++ b/lib/llm/providers/gemini/response_parser.rb @@ -16,9 +16,11 @@ def parse_completion(raw) { model: raw["modelVersion"], choices: raw["candidates"].map do + stop_reason = _1["finishReason"] LLM::Message.new( _1.dig("content", "role"), - {text: _1.dig("content", "parts", 0, "text")} + {text: _1.dig("content", "parts", 0, "text")}, + {stop_reason:} ) end, prompt_tokens: raw.dig("usageMetadata", "promptTokenCount"), diff --git a/spec/gemini/completion_spec.rb b/spec/gemini/completion_spec.rb index a1940e00..7e037cb2 100644 --- a/spec/gemini/completion_spec.rb +++ b/spec/gemini/completion_spec.rb @@ -111,6 +111,10 @@ total_tokens: 12 ) end + + it "has stop_reason" do + expect(completion.choices.first.stop_reason).to eq("STOP") + end end context "with an unauthorized error", :unauthorized do From 25ff191213af726efbc5759b0cc7ac7cddca8b10 Mon Sep 17 00:00:00 2001 From: Antar Azri Date: Wed, 20 Nov 2024 13:41:38 +0100 Subject: [PATCH 5/5] feat: add `stop_reason` for Ollama completion message Note that for some reason Ollama does not always respond with `done_reason`. So that needs to be investigated further --- lib/llm/providers/ollama/response_parser.rb | 2 +- spec/ollama/completion_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/llm/providers/ollama/response_parser.rb b/lib/llm/providers/ollama/response_parser.rb index 55d70427..3fa5a77f 100644 --- a/lib/llm/providers/ollama/response_parser.rb +++ b/lib/llm/providers/ollama/response_parser.rb @@ -7,7 +7,7 @@ module ResponseParser def parse_completion(raw) { model: raw["model"], - choices: [LLM::Message.new(*raw["message"].values_at("role", "content"))], + choices: [LLM::Message.new(*raw["message"].values_at("role", "content"), {stop_reason: raw["done_reason"]})], prompt_tokens: raw.dig("prompt_eval_count"), completion_tokens: raw.dig("eval_count") } diff --git a/spec/ollama/completion_spec.rb b/spec/ollama/completion_spec.rb index b9512f2a..7a2d2d69 100644 --- a/spec/ollama/completion_spec.rb +++ b/spec/ollama/completion_spec.rb @@ -18,6 +18,7 @@ "content": "Hello! How are you today?" }, "done": true, + "done_reason": "stop", "total_duration": 5191566416, "load_duration": 2154458, "prompt_eval_count": 26, @@ -87,6 +88,10 @@ total_tokens: 324 ) end + + it "has stop reason for first choice" do + expect(completion.choices.first.stop_reason).to eq("stop") + end end # context "with an unauthorized error", :unauthorized do