From d4109b2b3f4a259e84d857a102fc9fec0e6d3528 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 17:41:38 +0100 Subject: [PATCH 1/8] Introduce OpenAI action --- .../actions/common/openai_generate_action.rb | 111 +++++++++++++++++ spec/openai_generate_action_spec.rb | 117 ++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb create mode 100644 spec/openai_generate_action_spec.rb diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb new file mode 100644 index 000000000..a95fe6635 --- /dev/null +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -0,0 +1,111 @@ +require 'fastlane/action' +require 'net/http' +require 'json' + +module Fastlane + module Actions + class OpenaiGenerateAction < Action + OPENAI_API_ENDPOINT = URI('https://api.openai.com/v1/chat/completions').freeze + + RELEASE_NOTES_PROMPT = <<~PROMPT.freeze + Act like a mobile app marketer who wants to prepare release notes for Google Play and App Store. + Do not write it point by point and keep it under 350 characters. It should be a unique paragraph. + + When provided a list, use the number of any potential "*" in brackets at the start of each item as indicator of importance. + Ignore items starting with "[Internal]", and ignore links to GitHub. + PROMPT + + def self.run(params) + api_token = params[:api_token] + prompt = params[:prompt] + prompt = RELEASE_NOTES_PROMPT if prompt == ':release_notes' + question = params[:question] + + headers = { + 'Content-Type': 'application/json', + Authorization: "Bearer #{api_token}" + } + body = request_body(prompt: prompt, question: question) + + response = Net::HTTP.post(OPENAI_API_ENDPOINT, body, headers) + + case response + when Net::HTTPOK + json = JSON.parse(response.body) + best_choice = json['choices']&.first + UI.abort_with_message!("Unable to parse OpenAPI response\n#{json}") if best_choice.nil? + best_choice['message']['content'] + else + UI.user_error!("Error in OpenAPI API response: #{response}. #{response.body}") + end + end + + def self.request_body(prompt:, question:) + { + model: 'gpt-4o', + response_format: { type: 'text' }, + temperature: 1, + max_tokens: 2048, + top_p: 1, + messages: [ + format_message(role: 'system', text: prompt), + format_message(role: 'user', text: question), + ].compact + }.to_json + end + + def self.format_message(role:, text:) + return nil if text.nil? || text.empty? + + { + role: role, + content: [{ type: 'text', text: text }] + } + end + + def self.description + 'Use OpenAI API to generate response to a prompt' + end + + def self.authors + ['Automattic'] + end + + def self.return_value + 'The response from the prompt as returned by OpenAI API' + end + + def self.details + <<~DETAILS + Uses the OpenAPI API to generate response to a prompt. + Can be used to e.g. ask it to generate Release Notes based on a bullet point technical changelog or similar. + DETAILS + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :prompt, + description: 'The internal top-level instructions to give to the model to tell it how to behave. Use `:release_notes` to use a predefined prompt to ask to write release notes from a changelog list', + optional: true, + default_value: nil, + type: String), + FastlaneCore::ConfigItem.new(key: :question, + description: 'The user message to ask the question to the OpenAI model', + optional: false, + default_value: nil, + type: String), + FastlaneCore::ConfigItem.new(key: :api_token, + description: 'The OpenAPI API Token to use for the request', + env_name: 'OPENAPI_API_TOKEN', + optional: false, + sensitive: true, + type: String), + ] + end + + def self.is_supported?(platform) + true + end + end + end +end diff --git a/spec/openai_generate_action_spec.rb b/spec/openai_generate_action_spec.rb new file mode 100644 index 000000000..e60c73bb8 --- /dev/null +++ b/spec/openai_generate_action_spec.rb @@ -0,0 +1,117 @@ +require 'spec_helper' + +describe Fastlane::Actions::OpenaiGenerateAction do + let(:fake_token) { 'sk-proj-faketok' } + let(:endpoint) { Fastlane::Actions::OpenaiGenerateAction::OPENAI_API_ENDPOINT } + let(:release_notes_prompt) { Fastlane::Actions::OpenaiGenerateAction::RELEASE_NOTES_PROMPT } + + def stubbed_response(text) + <<~JSON + { + "id": "chatcmpl-Aa2NPY4sSWF5eKoW1aFBJmfc78y9p", + "object": "chat.completion", + "created": 1733152307, + "model": "gpt-4o-2024-08-06", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": #{text.to_json}, + "refusal": null + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 91, + "completion_tokens": 68, + "total_tokens": 159, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "system_fingerprint": "fp_831e067d82" + } + JSON + end + + def run_test(prompt_param:, question_param:, expected_prompt:, expected_response:) + expected_req_body = described_class.request_body(prompt: expected_prompt, question: question_param) + + stub = stub_request(:post, endpoint) + .with(body: expected_req_body) + .to_return(status: 200, body: stubbed_response(expected_response)) + + result = run_described_fastlane_action( + api_token: fake_token, + prompt: prompt_param, + question: question_param + ) + + # Ensure the body of the request contains the expected JSON data + messages = JSON.parse(expected_req_body)['messages'] + if expected_prompt.nil? || expected_prompt.empty? + expect(messages.length).to eq(1) + expect(messages[0]['role']).to eq('user') + expect(messages[0]['content']).to eq(['type' => 'text', 'text' => question_param]) + else + expect(messages.length).to eq(2) + expect(messages[0]['role']).to eq('system') + expect(messages[0]['content']).to eq(['type' => 'text', 'text' => expected_prompt]) + expect(messages[1]['role']).to eq('user') + expect(messages[1]['content']).to eq(['type' => 'text', 'text' => question_param]) + end + + # Ensure the request has been made and the response is as expected + expect(stub).to have_been_requested + result + end + + it 'calls the API with no prompt' do + result = run_test( + prompt_param: '', + question_param: 'Say Hi', + expected_prompt: nil, + expected_response: 'Hello! How can I assist you today?' + ) + + expect(result).to eq('Hello! How can I assist you today?') + end + + it 'calls the API with :release_notes prompt' do + changelog = <<~CHANGELOG + - [Internal] Fetch remote FF on site change [https://github.com/woocommerce/woocommerce-android/pull/12751] + - [**] Improve barcode scanner reading accuracy [https://github.com/woocommerce/woocommerce-android/pull/12673] + - [Internal] AI product creation banner is removed [https://github.com/woocommerce/woocommerce-android/pull/12705] + - [*] [Login] Fix an issue where the app doesn't show the correct error screen when application passwords are disabled [https://github.com/woocommerce/woocommerce-android/pull/12717] + - [**] Fixed bug with coupons disappearing from the order creation screen unexpectedly [https://github.com/woocommerce/woocommerce-android/pull/12724] + - [Internal] Fixes crash [https://github.com/woocommerce/woocommerce-android/issues/12715] + - [*] Fixed incorrect instructions on "What is Tap to Pay" screen in the Payments section [https://github.com/woocommerce/woocommerce-android/pull/12709] + - [***] Merchants can now view and edit custom fields of their products and orders from the app [https://github.com/woocommerce/woocommerce-android/issues/12207] + - [*] Fix size of the whats new announcement dialog [https://github.com/woocommerce/woocommerce-android/pull/12692] + - [*] Enables Blaze survey [https://github.com/woocommerce/woocommerce-android/pull/12761] + CHANGELOG + + expected_response = <<~TEXT + Exciting updates are here! We've enhanced the barcode scanner for optimal accuracy and resolved the issue with coupons vanishing during order creation. Most significantly, merchants can now effortlessly view and edit custom fields for products and orders directly within the app. Additionally, we've improved error handling on login and fixed various UI inconsistencies. Enjoy a smoother experience! + TEXT + + result = run_test( + prompt_param: ':release_notes', + question_param: "Help me write release notes for the following items:\n#{changelog}", + expected_prompt: release_notes_prompt, + expected_response: expected_response + ) + + expect(result).to eq(expected_response) + end +end From 5a6fd7eb269f97769d49fa38276a8212aa6cdd73 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 18:27:17 +0100 Subject: [PATCH 2/8] Refactor predefined prompts (allow Symbols) --- .../actions/common/openai_generate_action.rb | 32 +++++++++++++------ spec/openai_generate_action_spec.rb | 4 +-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb index a95fe6635..bd704e740 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -7,18 +7,20 @@ module Actions class OpenaiGenerateAction < Action OPENAI_API_ENDPOINT = URI('https://api.openai.com/v1/chat/completions').freeze - RELEASE_NOTES_PROMPT = <<~PROMPT.freeze - Act like a mobile app marketer who wants to prepare release notes for Google Play and App Store. - Do not write it point by point and keep it under 350 characters. It should be a unique paragraph. + PREDEFINED_PROMPTS = { + release_notes: <<~PROMPT.freeze + Act like a mobile app marketer who wants to prepare release notes for Google Play and App Store. + Do not write it point by point and keep it under 350 characters. It should be a unique paragraph. - When provided a list, use the number of any potential "*" in brackets at the start of each item as indicator of importance. - Ignore items starting with "[Internal]", and ignore links to GitHub. - PROMPT + When provided a list, use the number of any potential "*" in brackets at the start of each item as indicator of importance. + Ignore items starting with "[Internal]", and ignore links to GitHub. + PROMPT + }.freeze def self.run(params) api_token = params[:api_token] prompt = params[:prompt] - prompt = RELEASE_NOTES_PROMPT if prompt == ':release_notes' + prompt = PREDEFINED_PROMPTS[prompt] if PREDEFINED_PROMPTS.key?(prompt) question = params[:question] headers = { @@ -82,13 +84,25 @@ def self.details DETAILS end + def self.available_prompt_symbols + PREDEFINED_PROMPTS.keys.map { |v| "`:#{v}`" }.join(',') + end + def self.available_options [ FastlaneCore::ConfigItem.new(key: :prompt, - description: 'The internal top-level instructions to give to the model to tell it how to behave. Use `:release_notes` to use a predefined prompt to ask to write release notes from a changelog list', + description: 'The internal top-level instructions to give to the model to tell it how to behave. ' \ + + "Use a Ruby Symbol from one of [#{available_prompt_symbols}] to use a predefined prompt instead of writing your own", optional: true, default_value: nil, - type: String), + type: String, + skip_type_validation: true, + verify_block: proc do |value| + next if value.is_a?(String) + next if PREDEFINED_PROMPTS.include?(value) + + UI.user_error!("Parameter `prompt` can only be a String or one of the following Symbols: [#{available_prompt_symbols}]") + end), FastlaneCore::ConfigItem.new(key: :question, description: 'The user message to ask the question to the OpenAI model', optional: false, diff --git a/spec/openai_generate_action_spec.rb b/spec/openai_generate_action_spec.rb index e60c73bb8..1a5c0cd5e 100644 --- a/spec/openai_generate_action_spec.rb +++ b/spec/openai_generate_action_spec.rb @@ -3,7 +3,7 @@ describe Fastlane::Actions::OpenaiGenerateAction do let(:fake_token) { 'sk-proj-faketok' } let(:endpoint) { Fastlane::Actions::OpenaiGenerateAction::OPENAI_API_ENDPOINT } - let(:release_notes_prompt) { Fastlane::Actions::OpenaiGenerateAction::RELEASE_NOTES_PROMPT } + let(:release_notes_prompt) { Fastlane::Actions::OpenaiGenerateAction::PREDEFINED_PROMPTS[:release_notes] } def stubbed_response(text) <<~JSON @@ -106,7 +106,7 @@ def run_test(prompt_param:, question_param:, expected_prompt:, expected_response TEXT result = run_test( - prompt_param: ':release_notes', + prompt_param: :release_notes, question_param: "Help me write release notes for the following items:\n#{changelog}", expected_prompt: release_notes_prompt, expected_response: expected_response From 96fe17026f058326e84f5ba2ddff16692008aa44 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 18:30:24 +0100 Subject: [PATCH 3/8] Improve parsing logic --- .../actions/common/openai_generate_action.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb index bd704e740..586a6a77f 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -34,9 +34,7 @@ def self.run(params) case response when Net::HTTPOK json = JSON.parse(response.body) - best_choice = json['choices']&.first - UI.abort_with_message!("Unable to parse OpenAPI response\n#{json}") if best_choice.nil? - best_choice['message']['content'] + json['choices']&.first&.dig('message', 'content') else UI.user_error!("Error in OpenAPI API response: #{response}. #{response.body}") end From 942813da7693a2417150de8ff3f7b251083ec3c1 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 18:35:32 +0100 Subject: [PATCH 4/8] Add example `Fastfile` call as part of code doc --- .../actions/common/openai_generate_action.rb | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb index 586a6a77f..310bcf10b 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -63,6 +63,10 @@ def self.format_message(role:, text:) } end + ##################################################### + # @!group Documentation + ##################################################### + def self.description 'Use OpenAI API to generate response to a prompt' end @@ -72,7 +76,7 @@ def self.authors end def self.return_value - 'The response from the prompt as returned by OpenAI API' + 'The response text from the prompt as returned by OpenAI API' end def self.details @@ -82,6 +86,20 @@ def self.details DETAILS end + def self.examples + [ + <<~EXEMPLE, + items = extract_release_notes_for_version(version: app_version, release_notes_file_path: 'RELEASE-NOTES.txt') + nice_changelog = openai_generate( + prompt: ':release_notes', # Uses the pre-crafted prompt for App Store / Play Store release notes + question: "Help me write release notes for the following items:\n#{items}" + api_token = get_required_env('OPENAI_API_TOKEN') + ) + File.write(File.join('fastlane', 'metadata', 'android', en-US', 'changelogs', 'default.txt'), nice_changelog) + EXEMPLE + ] + end + def self.available_prompt_symbols PREDEFINED_PROMPTS.keys.map { |v| "`:#{v}`" }.join(',') end @@ -115,7 +133,7 @@ def self.available_options ] end - def self.is_supported?(platform) + def self.is_supported?(_platform) true end end From 9d0e291fbf67afb863bc22495aba4c510b77476d Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 18:36:51 +0100 Subject: [PATCH 5/8] Add CHANGELOG entry --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bce107126..16d61ca8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ _None_ ### New Features -_None_ +- Introduce new `openai_generate` action to get responses to a prompt/question from OpenAI API. [#621] ### Bug Fixes @@ -24,7 +24,7 @@ _None_ ### Bug Fixes -- `DateVersionCalculator`: move next year calculation decision to the clients [#619] +- `DateVersionCalculator`: move next year calculation decision to the clients. [#619] ### Internal Changes @@ -34,8 +34,8 @@ _None_ ### Bug Fixes -- Fix `check_fonts_installed` step in `create_promo_screenshots` [#615] -- Fix broken `draw_text_to_canvas` method for `create_promo_screenshots` [#614] +- Fix `check_fonts_installed` step in `create_promo_screenshots`. [#615] +- Fix broken `draw_text_to_canvas` method for `create_promo_screenshots`. [#614] ## 12.3.2 From b0e55f029cc754320cc1d81f5b3e9f8769ab3279 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Mon, 2 Dec 2024 20:23:16 +0100 Subject: [PATCH 6/8] Fix `s/OpenAPI/OpenAI/` typos And syntax error in example code --- .../actions/common/openai_generate_action.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb index 310bcf10b..7c6126338 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -36,7 +36,7 @@ def self.run(params) json = JSON.parse(response.body) json['choices']&.first&.dig('message', 'content') else - UI.user_error!("Error in OpenAPI API response: #{response}. #{response.body}") + UI.user_error!("Error in OpenAI API response: #{response}. #{response.body}") end end @@ -81,7 +81,7 @@ def self.return_value def self.details <<~DETAILS - Uses the OpenAPI API to generate response to a prompt. + Uses the OpenAI API to generate response to a prompt. Can be used to e.g. ask it to generate Release Notes based on a bullet point technical changelog or similar. DETAILS end @@ -91,9 +91,9 @@ def self.examples <<~EXEMPLE, items = extract_release_notes_for_version(version: app_version, release_notes_file_path: 'RELEASE-NOTES.txt') nice_changelog = openai_generate( - prompt: ':release_notes', # Uses the pre-crafted prompt for App Store / Play Store release notes - question: "Help me write release notes for the following items:\n#{items}" - api_token = get_required_env('OPENAI_API_TOKEN') + prompt: :release_notes, # Uses the pre-crafted prompt for App Store / Play Store release notes + question: "Help me write release notes for the following items:\n#{items}", + api_token: get_required_env('OPENAI_API_TOKEN') ) File.write(File.join('fastlane', 'metadata', 'android', en-US', 'changelogs', 'default.txt'), nice_changelog) EXEMPLE @@ -125,8 +125,8 @@ def self.available_options default_value: nil, type: String), FastlaneCore::ConfigItem.new(key: :api_token, - description: 'The OpenAPI API Token to use for the request', - env_name: 'OPENAPI_API_TOKEN', + description: 'The OpenAI API Token to use for the request', + env_name: 'OPENAI_API_TOKEN', optional: false, sensitive: true, type: String), From 11a7b37df817ec0fab76ffaabe48a673bdf0c2a5 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Wed, 4 Dec 2024 11:09:29 +0100 Subject: [PATCH 7/8] Fix typo Co-authored-by: Ian Guedes Maia --- .../wpmreleasetoolkit/actions/common/openai_generate_action.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb index 7c6126338..3959bcee7 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb @@ -95,7 +95,7 @@ def self.examples question: "Help me write release notes for the following items:\n#{items}", api_token: get_required_env('OPENAI_API_TOKEN') ) - File.write(File.join('fastlane', 'metadata', 'android', en-US', 'changelogs', 'default.txt'), nice_changelog) + File.write(File.join('fastlane', 'metadata', 'android', 'en-US', 'changelogs', 'default.txt'), nice_changelog) EXEMPLE ] end From c829b8d6a0b1db0f459c4562ea966da81d287803 Mon Sep 17 00:00:00 2001 From: Olivier Halligon Date: Wed, 4 Dec 2024 11:16:14 +0100 Subject: [PATCH 8/8] Rename action to `openai_ask` --- .../{openai_generate_action.rb => openai_ask_action.rb} | 4 ++-- ...generate_action_spec.rb => openai_ask_action_spec.rb} | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) rename lib/fastlane/plugin/wpmreleasetoolkit/actions/common/{openai_generate_action.rb => openai_ask_action.rb} (98%) rename spec/{openai_generate_action_spec.rb => openai_ask_action_spec.rb} (92%) diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_ask_action.rb similarity index 98% rename from lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb rename to lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_ask_action.rb index 3959bcee7..9c09ed58e 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_generate_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_ask_action.rb @@ -4,7 +4,7 @@ module Fastlane module Actions - class OpenaiGenerateAction < Action + class OpenaiAskAction < Action OPENAI_API_ENDPOINT = URI('https://api.openai.com/v1/chat/completions').freeze PREDEFINED_PROMPTS = { @@ -90,7 +90,7 @@ def self.examples [ <<~EXEMPLE, items = extract_release_notes_for_version(version: app_version, release_notes_file_path: 'RELEASE-NOTES.txt') - nice_changelog = openai_generate( + nice_changelog = openai_ask( prompt: :release_notes, # Uses the pre-crafted prompt for App Store / Play Store release notes question: "Help me write release notes for the following items:\n#{items}", api_token: get_required_env('OPENAI_API_TOKEN') diff --git a/spec/openai_generate_action_spec.rb b/spec/openai_ask_action_spec.rb similarity index 92% rename from spec/openai_generate_action_spec.rb rename to spec/openai_ask_action_spec.rb index 1a5c0cd5e..46c79f671 100644 --- a/spec/openai_generate_action_spec.rb +++ b/spec/openai_ask_action_spec.rb @@ -1,9 +1,8 @@ require 'spec_helper' -describe Fastlane::Actions::OpenaiGenerateAction do +describe Fastlane::Actions::OpenaiAskAction do let(:fake_token) { 'sk-proj-faketok' } - let(:endpoint) { Fastlane::Actions::OpenaiGenerateAction::OPENAI_API_ENDPOINT } - let(:release_notes_prompt) { Fastlane::Actions::OpenaiGenerateAction::PREDEFINED_PROMPTS[:release_notes] } + let(:endpoint) { Fastlane::Actions::OpenaiAskAction::OPENAI_API_ENDPOINT } def stubbed_response(text) <<~JSON @@ -71,7 +70,7 @@ def run_test(prompt_param:, question_param:, expected_prompt:, expected_response expect(messages[1]['content']).to eq(['type' => 'text', 'text' => question_param]) end - # Ensure the request has been made and the response is as expected + # Ensure the request has been made and return the action response for it to be validated in calling test expect(stub).to have_been_requested result end @@ -108,7 +107,7 @@ def run_test(prompt_param:, question_param:, expected_prompt:, expected_response result = run_test( prompt_param: :release_notes, question_param: "Help me write release notes for the following items:\n#{changelog}", - expected_prompt: release_notes_prompt, + expected_prompt: Fastlane::Actions::OpenaiAskAction::PREDEFINED_PROMPTS[:release_notes], expected_response: expected_response )