Skip to content

Commit c3bab1e

Browse files
committed
Validate openai_ask tools parameter
1 parent 73e20e7 commit c3bab1e

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

lib/fastlane/plugin/wpmreleasetoolkit/actions/common/openai_ask_action.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def self.run(params)
4747
return parse_text_response(response)
4848
end
4949

50-
UI.user_error!('Parameter `tools` must be a non-empty Array when provided') if tools.empty?
50+
validate_tools_array!(tools)
5151
validate_tools!(tools)
5252
run_with_tools(
5353
prompt: prompt,
@@ -157,6 +157,10 @@ def self.validate_max_tool_iterations!(max_tool_iterations)
157157
UI.user_error!("Parameter `max_tool_iterations` must be >= 1 (got #{max_tool_iterations})") if max_tool_iterations < 1
158158
end
159159

160+
def self.validate_tools_array!(tools)
161+
UI.user_error!('Parameter `tools` must be a non-empty Array when provided') unless tools.is_a?(Array) && !tools.empty?
162+
end
163+
160164
def self.validate_tools!(tools)
161165
invalid_tools = tools.each_with_index.filter_map do |tool, index|
162166
type = tool_type(tool)
@@ -402,7 +406,7 @@ def self.available_options
402406
default_value: nil,
403407
type: Array,
404408
verify_block: proc do |value|
405-
UI.user_error!('Parameter `tools` must be a non-empty Array when provided') if value.empty?
409+
validate_tools_array!(value)
406410
validate_tools!(value)
407411
end),
408412
FastlaneCore::ConfigItem.new(key: :tool_handlers,

spec/openai_ask_action_spec.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def run_test(prompt_param:, question_param:, expected_prompt:, expected_response
454454
end
455455

456456
it 'returns a structured error tool result when the handler raises' do
457-
expect(UI).not_to receive(:verbose)
457+
expect(FastlaneCore::UI).not_to receive(:verbose)
458458

459459
tool_handlers = {
460460
'check_length' => ->(_args) { raise ArgumentError, 'bad args' }
@@ -475,7 +475,7 @@ def run_test(prompt_param:, question_param:, expected_prompt:, expected_response
475475
{ status: 200, body: second_response }
476476
)
477477

478-
expect(UI).to receive(:error).with(
478+
expect(FastlaneCore::UI).to receive(:error).with(
479479
satisfy do |message|
480480
message.include?("Handler for tool 'check_length' raised ArgumentError") &&
481481
!message.include?('bad args') &&
@@ -532,7 +532,7 @@ def to_json(*_args)
532532
{ status: 200, body: second_response }
533533
)
534534

535-
expect(UI).to receive(:error).with(
535+
expect(FastlaneCore::UI).to receive(:error).with(
536536
satisfy do |message|
537537
message.include?("Could not serialize tool result for 'check_length': RuntimeError") &&
538538
!message.include?('cannot serialize')
@@ -578,7 +578,7 @@ def to_json(*_args)
578578
{ status: 200, body: second_response }
579579
)
580580

581-
expect(UI).to receive(:error).with(
581+
expect(FastlaneCore::UI).to receive(:error).with(
582582
satisfy do |message|
583583
message.include?("Invalid JSON arguments for tool 'check_length'") &&
584584
!message.include?('secret_token=abc123')
@@ -601,8 +601,8 @@ def to_json(*_args)
601601
end
602602

603603
it 'does not log raw tool arguments even when verbose mode is enabled' do
604-
expect(UI).to receive(:error).with(/Raw payload omitted/)
605-
expect(UI).not_to receive(:verbose)
604+
expect(FastlaneCore::UI).to receive(:error).with(/Raw payload omitted/)
605+
expect(FastlaneCore::UI).not_to receive(:verbose)
606606

607607
result = described_class.execute_tool_call(
608608
{
@@ -623,7 +623,7 @@ def to_json(*_args)
623623
end
624624

625625
it 'returns a structured error tool result for unsupported returned tool call types' do
626-
expect(UI).to receive(:error).with(/Unsupported OpenAI tool call type 'custom'/)
626+
expect(FastlaneCore::UI).to receive(:error).with(/Unsupported OpenAI tool call type 'custom'/)
627627

628628
result = described_class.execute_tool_call(
629629
{
@@ -647,7 +647,7 @@ def to_json(*_args)
647647
end
648648

649649
it 'returns a clear structured error when a returned function tool call has no name' do
650-
expect(UI).to receive(:error).with(/missing a non-empty function.name/)
650+
expect(FastlaneCore::UI).to receive(:error).with(/missing a non-empty function.name/)
651651

652652
result = described_class.execute_tool_call(
653653
{
@@ -711,6 +711,17 @@ def to_json(*_args)
711711
end.to raise_error(FastlaneCore::Interface::FastlaneError, /tools.*non-empty Array/)
712712
end
713713

714+
it 'rejects non-array tools when run directly' do
715+
expect do
716+
described_class.run(
717+
api_token: fake_token,
718+
prompt: 'sys',
719+
question: 'q',
720+
tools: 'not a tools array'
721+
)
722+
end.to raise_error(FastlaneCore::Interface::FastlaneError, /tools.*non-empty Array/)
723+
end
724+
714725
it 'rejects unsupported tool definition types' do
715726
expect do
716727
described_class.run(

0 commit comments

Comments
 (0)