Skip to content
Draft
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
32 changes: 27 additions & 5 deletions packages/firebase_ai/firebase_ai/lib/src/live_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ class LiveServerContent implements LiveServerMessage {
/// [modelTurn] (optional): The content generated by the model.
/// [turnComplete] (optional): Indicates if the turn is complete.
/// [interrupted] (optional): Indicates if the generation was interrupted.
LiveServerContent({this.modelTurn, this.turnComplete, this.interrupted});
LiveServerContent(
{this.modelTurn,
this.turnComplete,
this.interrupted,
this.groundingMetadata});

// TODO(cynthia): Add accessor for media content
/// The content generated by the model.
Expand All @@ -129,6 +133,9 @@ class LiveServerContent implements LiveServerMessage {
/// Whether generation was interrupted. If true, indicates that a
/// client message has interrupted current model
final bool? interrupted;

/// Metadata specifies sources used to ground generated content.
final GroundingMetadata? groundingMetadata;
}

/// A tool call in a live stream.
Expand Down Expand Up @@ -170,10 +177,13 @@ class LiveServerToolCallCancellation implements LiveServerMessage {
/// ongoing generation.
class LiveServerResponse {
// ignore: public_member_api_docs
LiveServerResponse({required this.message});
LiveServerResponse({required this.message, this.usageMetadata});

/// The server message generated by the live model.
final LiveServerMessage message;

/// Usage metadata about the response(s).
final UsageMetadata? usageMetadata;
}

/// Represents realtime input from the client in a live stream.
Expand Down Expand Up @@ -286,7 +296,11 @@ class LiveClientToolResponse {
/// - A [LiveServerResponse] object representing the parsed message.
LiveServerResponse parseServerResponse(Object jsonObject) {
LiveServerMessage message = _parseServerMessage(jsonObject);
return LiveServerResponse(message: message);
UsageMetadata? usageMetadata;
if (jsonObject case {'usageMetadata': final Object usageMetadataJson}) {
usageMetadata = parseUsageMetadata(usageMetadataJson);
}
return LiveServerResponse(message: message, usageMetadata: usageMetadata);
}

LiveServerMessage _parseServerMessage(Object jsonObject) {
Expand All @@ -295,7 +309,6 @@ LiveServerMessage _parseServerMessage(Object jsonObject) {
}

Map<String, dynamic> json = jsonObject as Map<String, dynamic>;

if (json.containsKey('serverContent')) {
final serverContentJson = json['serverContent'] as Map<String, dynamic>;
Content? modelTurn;
Expand All @@ -306,7 +319,16 @@ LiveServerMessage _parseServerMessage(Object jsonObject) {
if (serverContentJson.containsKey('turnComplete')) {
turnComplete = serverContentJson['turnComplete'] as bool;
}
return LiveServerContent(modelTurn: modelTurn, turnComplete: turnComplete);
GroundingMetadata? groundingMetadata;
if (serverContentJson.containsKey('groundingMetadata')) {
final groundingMetadataJson =
serverContentJson['groundingMetadata'] as Map<String, dynamic>;
groundingMetadata = parseGroundingMetadata(groundingMetadataJson);
}
return LiveServerContent(
modelTurn: modelTurn,
turnComplete: turnComplete,
groundingMetadata: groundingMetadata);
} else if (json.containsKey('toolCall')) {
final toolContentJson = json['toolCall'] as Map<String, dynamic>;
List<FunctionCall> functionCalls = [];
Expand Down
Loading