Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/completions/llm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def presets
tokens: 800_000,
endpoint:
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash",
display_name: "Gemini 2.5 Pro",
display_name: "Gemini 2.5 Flash",
input_cost: 0.30,
output_cost: 2.50,
},
Expand Down Expand Up @@ -379,6 +379,12 @@ def generate(

model_params[:temperature] = temperature if temperature
model_params[:top_p] = top_p if top_p

# internals expect symbolized keys, so we normalize here
response_format =
JSON.parse(response_format.to_json, symbolize_names: true) if response_format &&
response_format.is_a?(Hash)

model_params[:response_format] = response_format if response_format
model_params.merge!(extra_model_params) if extra_model_params

Expand Down
18 changes: 18 additions & 0 deletions spec/lib/completions/endpoints/gemini_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ def tool_response
).to_return(status: 200, body: response)

structured_response = nil

llm.generate("Hello", response_format: schema, user: user) do |partial|
structured_response = partial
end
Expand All @@ -626,6 +627,23 @@ def tool_response
schema.dig(:json_schema, :schema).except(:additionalProperties),
)
expect(parsed.dig(:generationConfig, :responseMimeType)).to eq("application/json")

structured_response = nil
# once more but this time lets have the schema as string keys
llm.generate("Hello", response_format: schema.as_json, user: user) do |partial|
structured_response = partial
end

expect(structured_response.read_buffered_property(:key)).to eq("Hello!\n there")
expect(structured_response.read_buffered_property(:num)).to eq(42)

parsed = JSON.parse(req_body, symbolize_names: true)

# Verify that schema is passed following Gemini API specs.
expect(parsed.dig(:generationConfig, :responseSchema)).to eq(
schema.dig(:json_schema, :schema).except(:additionalProperties),
)
expect(parsed.dig(:generationConfig, :responseMimeType)).to eq("application/json")
end
end

Expand Down
22 changes: 21 additions & 1 deletion spec/system/ai_helper/ai_composer_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,27 @@ def trigger_composer_helper(content)
expect(ai_helper_menu).to have_custom_prompt_button_enabled
end

it "replaces the composed message with AI generated content" do
xit "replaces the composed message with AI generated content" do
# TODO: @keegan - this is a flake
# Failure/Error: super

# Playwright::TimeoutError:
# Timeout 11000ms exceeded.
# Call log:
# - attempting click action
# - 2 × waiting for element to be visible, enabled and stable
# - - element is not enabled
# - - retrying click action
# - - waiting 20ms
# - 2 × waiting for element to be visible, enabled and stable
# - - element is not enabled
# - - retrying click action
# - - waiting 100ms
# - 21 × waiting for element to be visible, enabled and stable
# - - element is not enabled
# - - retrying click action
# - - waiting 500ms

trigger_composer_helper(input)
ai_helper_menu.fill_custom_prompt(custom_prompt_input)

Expand Down
Loading