Show citations at the end of each turn (#7350)

This commit is contained in:
Tommaso Sciortino
2025-08-28 16:42:54 -07:00
committed by GitHub
parent 648ab84b21
commit 71ad272a1b
8 changed files with 262 additions and 24 deletions
+1
View File
@@ -45,6 +45,7 @@ const MIGRATION_MAP: Record<string, string> = {
hideFooter: 'ui.hideFooter',
showMemoryUsage: 'ui.showMemoryUsage',
showLineNumbers: 'ui.showLineNumbers',
showCitations: 'ui.showCitations',
accessibility: 'ui.accessibility',
ideMode: 'ide.enabled',
hasSeenIdeIntegrationNudge: 'ide.hasSeenNudge',
@@ -219,6 +219,15 @@ export const SETTINGS_SCHEMA = {
description: 'Show line numbers in the chat.',
showInDialog: true,
},
showCitations: {
type: 'boolean',
label: 'Show Citations',
category: 'UI',
requiresRestart: false,
default: false,
description: 'Show citations for generated text in the chat.',
showInDialog: true,
},
accessibility: {
type: 'object',
label: 'Accessibility',
+1
View File
@@ -1609,6 +1609,7 @@ describe('App UI', () => {
_history,
_addItem,
_config,
_settings,
_onDebugMessage,
_handleSlashCommand,
_shellModeActive,
+1
View File
@@ -639,6 +639,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
history,
addItem,
config,
settings,
setDebugMessage,
handleSlashCommand,
shellModeActive,
@@ -277,6 +277,7 @@ describe('useGeminiStream', () => {
props.history,
props.addItem,
props.config,
props.loadedSettings,
props.onDebugMessage,
props.handleSlashCommand,
props.shellModeActive,
@@ -438,6 +439,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -517,6 +519,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -625,6 +628,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -734,6 +738,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -863,6 +868,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1174,6 +1180,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1227,6 +1234,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
testConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1277,6 +1285,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1325,6 +1334,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1374,6 +1384,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1513,6 +1524,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false, // shellModeActive
@@ -1577,6 +1589,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1655,6 +1668,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
@@ -1709,6 +1723,7 @@ describe('useGeminiStream', () => {
[],
mockAddItem,
mockConfig,
mockLoadedSettings,
mockOnDebugMessage,
mockHandleSlashCommand,
false,
+28 -8
View File
@@ -7,15 +7,15 @@
import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
import type {
Config,
GeminiClient,
ServerGeminiStreamEvent as GeminiEvent,
ServerGeminiContentEvent as ContentEvent,
ServerGeminiErrorEvent as ErrorEvent,
ServerGeminiChatCompressedEvent,
ServerGeminiFinishedEvent,
ToolCallRequestInfo,
EditorType,
GeminiClient,
ServerGeminiChatCompressedEvent,
ServerGeminiContentEvent as ContentEvent,
ServerGeminiFinishedEvent,
ServerGeminiStreamEvent as GeminiEvent,
ThoughtSummary,
ToolCallRequestInfo,
GeminiErrorEventValue,
} from '@google/gemini-cli-core';
import {
GeminiEventType as ServerGeminiEventType,
@@ -60,6 +60,7 @@ import {
} from './useReactToolScheduler.js';
import { useSessionStats } from '../contexts/SessionContext.js';
import { useKeypress } from './useKeypress.js';
import type { LoadedSettings } from '../../config/settings.js';
enum StreamProcessingStatus {
Completed,
@@ -76,6 +77,7 @@ export const useGeminiStream = (
history: HistoryItem[],
addItem: UseHistoryManagerReturn['addItem'],
config: Config,
settings: LoadedSettings,
onDebugMessage: (message: string) => void,
handleSlashCommand: (
cmd: PartListUnion,
@@ -463,7 +465,7 @@ export const useGeminiStream = (
);
const handleErrorEvent = useCallback(
(eventValue: ErrorEvent['value'], userMessageTimestamp: number) => {
(eventValue: GeminiErrorEventValue, userMessageTimestamp: number) => {
if (pendingHistoryItemRef.current) {
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
setPendingHistoryItem(null);
@@ -486,6 +488,20 @@ export const useGeminiStream = (
[addItem, pendingHistoryItemRef, setPendingHistoryItem, config, setThought],
);
const handleCitationEvent = useCallback(
(text: string, userMessageTimestamp: number) => {
if (!settings?.merged?.ui?.showCitations) {
return;
}
if (pendingHistoryItemRef.current) {
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
setPendingHistoryItem(null);
}
addItem({ type: MessageType.INFO, text }, userMessageTimestamp);
},
[addItem, pendingHistoryItemRef, setPendingHistoryItem, settings],
);
const handleFinishedEvent = useCallback(
(event: ServerGeminiFinishedEvent, userMessageTimestamp: number) => {
const finishReason = event.value;
@@ -611,6 +627,9 @@ export const useGeminiStream = (
userMessageTimestamp,
);
break;
case ServerGeminiEventType.Citation:
handleCitationEvent(event.value, userMessageTimestamp);
break;
case ServerGeminiEventType.LoopDetected:
// handle later because we want to move pending history to history
// before we add loop detected message to history
@@ -636,6 +655,7 @@ export const useGeminiStream = (
handleChatCompressionEvent,
handleFinishedEvent,
handleMaxSessionTurnsEvent,
handleCitationEvent,
],
);