Skip to content

Commit 5d09ba3

Browse files
committed
Correctly implement citation merging for gemini
Fixes #358
1 parent 5f07aa7 commit 5d09ba3

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ellmer (development version)
22

3+
* `chat_gemini()` can now handle responses that include citation metadata
4+
(#358).
5+
36
* `live_browser()` now initializes `shinychat::chat_ui()` with the messages from
47
the chat turns, rather than replaying the turns server-side (#381).
58

R/provider-gemini.R

+5
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ merge_optional <- function(merge_func) {
325325
function(left, right, path = NULL) {
326326
if (is.null(left) && is.null(right)) {
327327
NULL
328+
} else if (is.null(left)) {
329+
right
330+
} else if (is.null(right)) {
331+
left
328332
} else {
329333
merge_func(left, right, path)
330334
}
@@ -405,6 +409,7 @@ merge_parts <- function() {
405409
}
406410

407411
# Put it all together...
412+
# https://ai.google.dev/api/generate-content#v1beta.GenerateContentResponse
408413
merge_gemini_chunks <- merge_objects(
409414
candidates = merge_candidate_lists(
410415
content = merge_objects(

tests/testthat/test-provider-gemini.R

+29
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,32 @@ test_that("can merge text output", {
7676
))
7777
expect_equal(out$candidates[[1]]$finishReason, "STOP")
7878
})
79+
80+
test_that("can handle citations", {
81+
# based on "Write me a 5-paragraph essay on the history of the tidyverse."
82+
messages <- c(
83+
'{"candidates": [{"content": {"parts": [{"text": "a"}]}, "role": "model"}]}',
84+
'{"candidates": [{
85+
"content": {"parts": [{"text": "a"}]},
86+
"role": "model",
87+
"citationMetadata": {
88+
"citationSources": [
89+
{
90+
"startIndex": 1,
91+
"endIndex": 2,
92+
"uri": "https://example.com",
93+
"license": ""
94+
}
95+
]
96+
}
97+
}]}'
98+
)
99+
chunks <- lapply(messages, jsonlite::parse_json)
100+
101+
out <- merge_gemini_chunks(chunks[[1]], chunks[[2]])
102+
source <- out$candidates[[1]]$citationMetadata$citationSources[[1]]
103+
expect_equal(source$startIndex, 1)
104+
expect_equal(source$endIndex, 2)
105+
expect_equal(source$uri, "https://example.com")
106+
expect_equal(source$license, "")
107+
})

0 commit comments

Comments
 (0)