diff --git a/firebase_functions_genkit/.gitignore b/firebase_functions_genkit/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/firebase_functions_genkit/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/firebase_functions_genkit/CHANGELOG.md b/firebase_functions_genkit/CHANGELOG.md new file mode 100644 index 0000000..a0712a7 --- /dev/null +++ b/firebase_functions_genkit/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.1.0 + +- Initial version. diff --git a/firebase_functions_genkit/README.md b/firebase_functions_genkit/README.md new file mode 100644 index 0000000..b399a4c --- /dev/null +++ b/firebase_functions_genkit/README.md @@ -0,0 +1,3 @@ +Extension on firebase functions to use genkit. + +Not included in firebase functions itself for more flexibility and reduced deps. \ No newline at end of file diff --git a/firebase_functions_genkit/analysis_options.yaml b/firebase_functions_genkit/analysis_options.yaml new file mode 100644 index 0000000..5c13630 --- /dev/null +++ b/firebase_functions_genkit/analysis_options.yaml @@ -0,0 +1,10 @@ +include: package:dart_flutter_team_lints/analysis_options.yaml + +linter: + rules: + - prefer_final_locals + - unnecessary_parenthesis + - prefer_expression_function_bodies + - document_ignores + - parameter_assignments + - prefer_final_in_for_each diff --git a/firebase_functions_genkit/example/README.md b/firebase_functions_genkit/example/README.md new file mode 100644 index 0000000..c66feb0 --- /dev/null +++ b/firebase_functions_genkit/example/README.md @@ -0,0 +1 @@ +Sample of creating a genkit flow and setting it up for an http trigger. \ No newline at end of file diff --git a/firebase_functions_genkit/example/bin/example.dart b/firebase_functions_genkit/example/bin/example.dart new file mode 100644 index 0000000..7dea0ef --- /dev/null +++ b/firebase_functions_genkit/example/bin/example.dart @@ -0,0 +1,51 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:firebase_functions/firebase_functions.dart'; +import 'package:firebase_functions_genkit/firebase_functions_genkit.dart'; +import 'package:genkit/genkit.dart'; +import 'package:genkit_google_genai/genkit_google_genai.dart'; + +const name = 'jokeTeller'; + +void main(List args) { + final gemini = googleAI(); + final ai = Genkit(plugins: [gemini]); + final flow = ai.defineFlow( + name: name, + inputSchema: .string(), + outputSchema: .string(), + streamSchema: .string(), + fn: (jokeType, context) async { + final prompt = 'Tell me a $jokeType joke.'; + + /// gemini.model does not have a generic type + // ignore: inference_failure_on_function_invocation + final stream = ai.generateStream( + model: gemini.model('gemini-2.5-flash'), + prompt: prompt, + ); + await stream.forEach((chunk) => context.sendChunk(chunk.text)); + return stream.result.text; + }, + ); + + fireUp(args, (firebase) { + firebase.https.onCallGenkit( + name: name, + flow: flow, + contextProvider: (request) => {'auth': request.auth?.token?['email']}, + ); + }); +} diff --git a/firebase_functions_genkit/example/pubspec.yaml b/firebase_functions_genkit/example/pubspec.yaml new file mode 100644 index 0000000..d2b8f6a --- /dev/null +++ b/firebase_functions_genkit/example/pubspec.yaml @@ -0,0 +1,12 @@ +name: example + +resolution: workspace + +environment: + sdk: ^3.10.0 + +dependencies: + firebase_functions: any + firebase_functions_genkit: any + genkit: any + genkit_google_genai: any diff --git a/firebase_functions_genkit/lib/firebase_functions_genkit.dart b/firebase_functions_genkit/lib/firebase_functions_genkit.dart new file mode 100644 index 0000000..c36f67c --- /dev/null +++ b/firebase_functions_genkit/lib/firebase_functions_genkit.dart @@ -0,0 +1,15 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export 'src/firebase_functions_genkit_base.dart'; diff --git a/firebase_functions_genkit/lib/src/firebase_functions_genkit_base.dart b/firebase_functions_genkit/lib/src/firebase_functions_genkit_base.dart new file mode 100644 index 0000000..da3e568 --- /dev/null +++ b/firebase_functions_genkit/lib/src/firebase_functions_genkit_base.dart @@ -0,0 +1,62 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:firebase_functions/firebase_functions.dart'; +import 'package:genkit/genkit.dart'; + +/// It's experimental as we can't semver package:meta +// ignore: experimental_member_use +import 'package:meta/meta.dart' show mustBeConst; + +/// Extension on [HttpsNamespace] to provide a seamless integration with Genkit. +extension GenkitExt on HttpsNamespace { + /// Registers a Genkit [flow] as a Firebase callable function. + /// + /// Automatically handles streaming and non-streaming responses based on + /// [CallableRequest.acceptsStreaming]. + /// + /// Use [contextProvider] to map properties from the Firebase + /// [CallableRequest] (such as authentication tokens) into the Genkit context. + void onCallGenkit({ + // Must repeat the name + /// It's experimental as we can't semver package:meta + // ignore: experimental_member_use + @mustBeConst required String name, + required Flow flow, + + /// It's experimental as we can't semver package:meta + // ignore: experimental_member_use + @mustBeConst CallableOptions? options = const CallableOptions(), + Map Function(CallableRequest)? contextProvider, + }) { + /// This is why we restate the name in the params above + // ignore: non_const_argument_for_const_parameter + onCall(name: name, options: options, (request, response) async { + if (request.acceptsStreaming) { + final actionStream = flow.stream( + request.data, + context: contextProvider?.call(request), + ); + await actionStream.forEach((chunk) => response.sendChunk(chunk)); + return CallableResult(actionStream.result); + } else { + final run = await flow.run( + request.data, + context: contextProvider?.call(request), + ); + return CallableResult(run.result); + } + }); + } +} diff --git a/firebase_functions_genkit/pubspec.yaml b/firebase_functions_genkit/pubspec.yaml new file mode 100644 index 0000000..772cab8 --- /dev/null +++ b/firebase_functions_genkit/pubspec.yaml @@ -0,0 +1,20 @@ +name: firebase_functions_genkit +description: A starting point for Dart libraries or applications. +version: 0.1.0 +repository: https://github.com/firebase/firebase-functions-dart + +publish_to: none + +workspace: + - example + +environment: + sdk: ^3.10.0 + +dependencies: + firebase_functions: ^0.5.0 + genkit: ^0.12.1 + meta: ^1.18.1 + +dev_dependencies: + dart_flutter_team_lints: ^3.5.2