genkit-plugin-firebase 0.3.2__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,8 +14,170 @@
14
14
  #
15
15
  # SPDX-License-Identifier: Apache-2.0
16
16
 
17
+ """Firebase plugin for Genkit.
17
18
 
18
- """Firebase Plugin for Genkit."""
19
+ This plugin provides Firebase integrations for Genkit, including Firestore
20
+ vector stores for RAG and Firebase telemetry export to Google Cloud.
21
+
22
+ Key Concepts (ELI5)::
23
+
24
+ ┌─────────────────────┬────────────────────────────────────────────────────┐
25
+ │ Concept │ ELI5 Explanation │
26
+ ├─────────────────────┼────────────────────────────────────────────────────┤
27
+ │ Firebase │ Google's app development platform. Like a │
28
+ │ │ toolbox for building apps with database, auth. │
29
+ ├─────────────────────┼────────────────────────────────────────────────────┤
30
+ │ Firestore │ A NoSQL database that syncs in real-time. │
31
+ │ │ Store data as flexible documents. │
32
+ ├─────────────────────┼────────────────────────────────────────────────────┤
33
+ │ Vector Store │ A database that can find "similar" items. │
34
+ │ │ Like Google but for YOUR documents. │
35
+ ├─────────────────────┼────────────────────────────────────────────────────┤
36
+ │ RAG │ Retrieval-Augmented Generation. AI looks up │
37
+ │ │ your docs before answering. Fewer hallucinations! │
38
+ ├─────────────────────┼────────────────────────────────────────────────────┤
39
+ │ Embeddings │ Convert text to numbers that capture meaning. │
40
+ │ │ "Cat" and "kitten" become similar numbers. │
41
+ ├─────────────────────┼────────────────────────────────────────────────────┤
42
+ │ Indexer │ Stores documents with their embeddings. │
43
+ │ │ Like adding books to a library catalog. │
44
+ ├─────────────────────┼────────────────────────────────────────────────────┤
45
+ │ Retriever │ Finds documents matching a query. │
46
+ │ │ Like a librarian finding relevant books. │
47
+ └─────────────────────┴────────────────────────────────────────────────────┘
48
+
49
+ Data Flow (RAG with Firestore)::
50
+
51
+ ┌─────────────────────────────────────────────────────────────────────────┐
52
+ │ HOW FIRESTORE VECTOR SEARCH WORKS │
53
+ │ │
54
+ │ STEP 1: INDEXING (Store your documents) │
55
+ │ ──────────────────────────────────────── │
56
+ │ Your Documents │
57
+ │ ["How to reset password", "Billing FAQ", ...] │
58
+ │ │ │
59
+ │ │ (1) Convert text to embeddings │
60
+ │ ▼ │
61
+ │ ┌─────────────────┐ │
62
+ │ │ Embedder │ "Reset password" → [0.12, -0.34, ...] │
63
+ │ │ (Gemini, etc.) │ │
64
+ │ └────────┬────────┘ │
65
+ │ │ │
66
+ │ │ (2) Store in Firestore with vectors │
67
+ │ ▼ │
68
+ │ ┌─────────────────┐ │
69
+ │ │ Firestore │ Document + embedding stored together │
70
+ │ │ (Vector Index) │ │
71
+ │ └─────────────────┘ │
72
+ │ │
73
+ │ STEP 2: RETRIEVAL (Find relevant documents) │
74
+ │ ───────────────────────────────────────────── │
75
+ │ User Query: "How do I change my password?" │
76
+ │ │ │
77
+ │ │ (3) Convert query to embedding │
78
+ │ ▼ │
79
+ │ ┌─────────────────┐ │
80
+ │ │ Embedder │ Query → [0.11, -0.33, ...] (similar!) │
81
+ │ └────────┬────────┘ │
82
+ │ │ │
83
+ │ │ (4) Find nearest neighbors │
84
+ │ ▼ │
85
+ │ ┌─────────────────┐ │
86
+ │ │ Firestore │ "Reset password" doc is 95% match! │
87
+ │ │ Vector Search │ │
88
+ │ └────────┬────────┘ │
89
+ │ │ │
90
+ │ │ (5) Return matching documents │
91
+ │ ▼ │
92
+ │ ┌─────────────────┐ │
93
+ │ │ Your App │ AI uses these docs to answer accurately │
94
+ │ └─────────────────┘ │
95
+ └─────────────────────────────────────────────────────────────────────────┘
96
+
97
+ Architecture Overview::
98
+
99
+ ┌─────────────────────────────────────────────────────────────────────────┐
100
+ │ Firebase Plugin │
101
+ ├─────────────────────────────────────────────────────────────────────────┤
102
+ │ Plugin Entry Point (__init__.py) │
103
+ │ ├── define_firestore_vector_store() - Create Firestore vector store │
104
+ │ └── add_firebase_telemetry() - Enable Cloud observability │
105
+ ├─────────────────────────────────────────────────────────────────────────┤
106
+ │ firestore.py - Firestore Vector Store │
107
+ │ ├── define_firestore_vector_store() - Main factory function │
108
+ │ ├── Firestore indexer implementation │
109
+ │ └── Firestore retriever implementation │
110
+ ├─────────────────────────────────────────────────────────────────────────┤
111
+ │ retriever.py - Retriever Implementation │
112
+ │ └── FirestoreRetriever (vector similarity search) │
113
+ └─────────────────────────────────────────────────────────────────────────┘
114
+
115
+ ┌─────────────────────────────────────────────────────────────────────────┐
116
+ │ Firestore Vector Store Flow │
117
+ │ │
118
+ │ Documents ──► Embedder ──► Firestore (with vector index) │
119
+ │ │
120
+ │ Query ──► Embedder ──► Firestore Vector Search ──► Results │
121
+ └─────────────────────────────────────────────────────────────────────────┘
122
+
123
+ Overview:
124
+ The Firebase plugin enables:
125
+ - Firestore as a vector store for document retrieval (RAG)
126
+ - Telemetry export to Google Cloud Trace and Monitoring
127
+
128
+ Key Components:
129
+ ┌─────────────────────────────────────────────────────────────────────────┐
130
+ │ Component │ Purpose │
131
+ ├──────────────────────────────┼──────────────────────────────────────────┤
132
+ │ define_firestore_vector_store│ Create a Firestore-backed vector store │
133
+ │ add_firebase_telemetry() │ Enable Cloud Trace/Monitoring export │
134
+ └──────────────────────────────┴──────────────────────────────────────────┘
135
+
136
+ Example:
137
+ Using Firestore vector store:
138
+
139
+ ```python
140
+ from genkit import Genkit
141
+ from genkit.plugins.firebase import define_firestore_vector_store
142
+
143
+ ai = Genkit(...)
144
+
145
+ # Define a Firestore vector store
146
+ store = define_firestore_vector_store(
147
+ ai,
148
+ name='my_store',
149
+ collection='documents',
150
+ embedder='vertexai/text-embedding-005',
151
+ )
152
+
153
+ # Index documents
154
+ await ai.index(indexer=store.indexer, documents=[...])
155
+
156
+ # Retrieve documents
157
+ docs = await ai.retrieve(retriever=store.retriever, query='...')
158
+ ```
159
+
160
+ Enabling telemetry:
161
+
162
+ ```python
163
+ from genkit.plugins.firebase import add_firebase_telemetry
164
+
165
+ # Export traces to Cloud Trace (disabled in dev mode by default)
166
+ add_firebase_telemetry()
167
+ ```
168
+
169
+ Caveats:
170
+ - Requires firebase-admin SDK and Google Cloud credentials
171
+ - Telemetry is disabled by default in development mode (GENKIT_ENV=dev)
172
+
173
+ See Also:
174
+ - Firestore: https://firebase.google.com/docs/firestore
175
+ - Genkit documentation: https://genkit.dev/
176
+ """
177
+
178
+ from genkit.plugins.google_cloud.telemetry.tracing import add_gcp_telemetry
179
+
180
+ from .firestore import define_firestore_vector_store
19
181
 
20
182
 
21
183
  def package_name() -> str:
@@ -27,4 +189,17 @@ def package_name() -> str:
27
189
  return 'genkit.plugins.firebase'
28
190
 
29
191
 
30
- __all__ = ['package_name']
192
+ def add_firebase_telemetry() -> None:
193
+ """Add Firebase telemetry export to Google Cloud Observability.
194
+
195
+ Exports traces to Cloud Trace and metrics to Cloud Monitoring.
196
+ In development (GENKIT_ENV=dev), telemetry is disabled by default.
197
+ """
198
+ add_gcp_telemetry(force_export=False)
199
+
200
+
201
+ __all__ = [
202
+ 'add_firebase_telemetry',
203
+ 'define_firestore_vector_store',
204
+ 'package_name',
205
+ ]
@@ -14,13 +14,19 @@
14
14
  #
15
15
  # SPDX-License-Identifier: Apache-2.0
16
16
 
17
+
18
+ """Firestore vector store operations for Genkit."""
19
+
17
20
  from collections.abc import Callable
18
- from typing import Any
19
21
 
22
+ from google.cloud import firestore
20
23
  from google.cloud.firestore_v1 import DocumentSnapshot
21
24
  from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
22
25
 
23
- from genkit.ai import GenkitRegistry, Plugin
26
+ from genkit.ai import Genkit
27
+ from genkit.blocks.retriever import RetrieverOptions, retriever_action_metadata
28
+ from genkit.core.action.types import ActionKind
29
+ from genkit.core.typing import DocumentPart
24
30
  from genkit.plugins.firebase.retriever import FirestoreRetriever
25
31
 
26
32
  from .constant import MetadataTransformFn
@@ -39,74 +45,59 @@ def firestore_action_name(name: str) -> str:
39
45
  return f'firestore/{name}'
40
46
 
41
47
 
42
- class FirestoreVectorStore(Plugin):
43
- """Firestore retriever plugin.
48
+ def define_firestore_vector_store(
49
+ ai: Genkit,
50
+ *,
51
+ name: str,
52
+ embedder: str,
53
+ embedder_options: dict[str, object] | None = None,
54
+ collection: str,
55
+ vector_field: str,
56
+ content_field: str | Callable[[DocumentSnapshot], list['DocumentPart']],
57
+ firestore_client: firestore.Client,
58
+ distance_measure: DistanceMeasure = DistanceMeasure.COSINE,
59
+ metadata_fields: list[str] | MetadataTransformFn | None = None,
60
+ ) -> str:
61
+ """Define and register a Firestore vector store retriever.
62
+
44
63
  Args:
45
- name: name if the retriever.
64
+ ai: The Genkit instance to register the retriever with.
65
+ name: Name of the retriever.
66
+ embedder: The embedder to use (e.g., 'vertexai/text-embedding-004').
67
+ embedder_options: Optional configuration to pass to the embedder.
46
68
  collection: The name of the Firestore collection to query.
47
69
  vector_field: The name of the field containing the vector embeddings.
48
70
  content_field: The name of the field containing the document content, you wish to return.
49
- embedder: The embedder to use with this retriever.
50
- embedder_options: Optional configuration to pass to the embedder.
51
- distance_measure: The distance measure to use when comparing vectors. Defaults to 'COSINE'.
52
71
  firestore_client: The Firestore database instance from which to query.
72
+ distance_measure: The distance measure to use when comparing vectors. Defaults to 'COSINE'.
53
73
  metadata_fields: Optional list of metadata fields to include.
54
- """
55
74
 
56
- name = 'firebaseFirestore'
57
-
58
- def __init__(
59
- self,
60
- name: str,
61
- firestore_client: Any,
62
- collection: str,
63
- vector_field: str,
64
- content_field: str | Callable[[DocumentSnapshot], list[dict[str, str]]],
65
- embedder: str,
66
- embedder_options: dict[str, Any] | None = None,
67
- distance_measure: DistanceMeasure = DistanceMeasure.COSINE,
68
- metadata_fields: list[str] | MetadataTransformFn | None = None,
69
- ):
70
- """Initialize the firestore plugin.
71
-
72
- Args:
73
- params: List of firestore retriever configurations.
74
- """
75
- self.name = name
76
- self.firestore_client = firestore_client
77
- self.collection = collection
78
- self.vector_field = vector_field
79
- self.content_field = content_field
80
- self.embedder = embedder
81
- self.embedder_options = embedder_options
82
- self.distance_measure = distance_measure
83
- self.metadata_fields = metadata_fields
84
-
85
- def initialize(self, ai: GenkitRegistry) -> None:
86
- """Initialize firestore plugin.
87
-
88
- Register actions with the registry making them available for use in the Genkit framework.
89
-
90
- Args:
91
- ai: The registry to register actions with.
92
-
93
- Returns:
94
- None
95
- """
96
- retriever = FirestoreRetriever(
97
- ai=ai,
98
- name=self.name,
99
- firestore_client=self.firestore_client,
100
- collection=self.collection,
101
- vector_field=self.vector_field,
102
- content_field=self.content_field,
103
- embedder=self.embedder,
104
- embedder_options=self.embedder_options,
105
- distance_measure=self.distance_measure,
106
- metadata_fields=self.metadata_fields,
107
- )
108
-
109
- return ai.define_retriever(
110
- name=firestore_action_name(self.name),
111
- fn=retriever.retrieve,
112
- )
75
+ Returns:
76
+ The registered retriever name.
77
+ """
78
+ retriever = FirestoreRetriever(
79
+ ai=ai,
80
+ name=name,
81
+ embedder=embedder,
82
+ embedder_options=embedder_options,
83
+ firestore_client=firestore_client,
84
+ collection=collection,
85
+ vector_field=vector_field,
86
+ content_field=content_field,
87
+ distance_measure=distance_measure,
88
+ metadata_fields=metadata_fields,
89
+ )
90
+
91
+ action_name = firestore_action_name(name)
92
+
93
+ ai.registry.register_action(
94
+ kind=ActionKind.RETRIEVER,
95
+ name=action_name,
96
+ fn=retriever.retrieve,
97
+ metadata=retriever_action_metadata(
98
+ name=action_name,
99
+ options=RetrieverOptions(label=name),
100
+ ).metadata,
101
+ )
102
+
103
+ return action_name
@@ -14,14 +14,18 @@
14
14
  #
15
15
  # SPDX-License-Identifier: Apache-2.0
16
16
 
17
+
18
+ """Firestore retriever implementation for Genkit."""
19
+
17
20
  from collections.abc import Callable
18
- from typing import Any
19
21
 
22
+ from google.cloud import firestore
20
23
  from google.cloud.firestore_v1 import DocumentSnapshot
21
24
  from google.cloud.firestore_v1.base_vector_query import DistanceMeasure
22
25
  from google.cloud.firestore_v1.vector import Vector
23
26
 
24
27
  from genkit.ai import Genkit
28
+ from genkit.core.typing import DocumentPart, TextPart
25
29
  from genkit.types import ActionRunContext, Document, GenkitError, RetrieverRequest, RetrieverResponse
26
30
 
27
31
  from .constant import MetadataTransformFn
@@ -31,45 +35,58 @@ class FirestoreRetriever:
31
35
  """Retrieves documents from Google Cloud Firestore using vector similarity search.
32
36
 
33
37
  Attributes:
34
- ai: An instance of the Genkit AI registry.
35
- params: A FirestoreRetrieverConfig object containing the configuration
36
- for the retriever
38
+ ai: Genkit instance used to embed queries.
39
+ name: Name of the retriever.
40
+ embedder: The embedder to use for query embeddings.
41
+ embedder_options: Optional configuration to pass to the embedder.
37
42
  firestore_client: The initialized Firestore client from the configuration.
43
+ collection: The name of the Firestore collection to query.
44
+ vector_field: The name of the field containing the vector embeddings.
45
+ content_field: The name of the field containing the document content.
46
+ distance_measure: The distance measure to use when comparing vectors.
47
+ metadata_fields: Optional list of metadata fields to include.
38
48
  """
39
49
 
40
50
  def __init__(
41
51
  self,
42
52
  ai: Genkit,
43
53
  name: str,
44
- firestore_client: Any,
54
+ embedder: str,
55
+ embedder_options: dict[str, object] | None,
56
+ firestore_client: firestore.Client,
45
57
  collection: str,
46
58
  vector_field: str,
47
- content_field: str | Callable[[DocumentSnapshot], list[dict[str, str]]],
48
- embedder: str,
49
- embedder_options: dict[str, Any] | None = None,
59
+ content_field: str | Callable[[DocumentSnapshot], list[DocumentPart]],
50
60
  distance_measure: DistanceMeasure = DistanceMeasure.COSINE,
51
61
  metadata_fields: list[str] | MetadataTransformFn | None = None,
52
- ):
62
+ ) -> None:
53
63
  """Initialize the FirestoreRetriever.
54
64
 
55
65
  Args:
56
- ai: An instance of the Genkit AI registry.
57
- params: A FirestoreRetrieverConfig object containing the configuration
58
- for the retriever
66
+ ai: Genkit instance used to embed queries.
67
+ name: Name of the retriever.
68
+ embedder: The embedder to use for query embeddings.
69
+ embedder_options: Optional configuration to pass to the embedder.
70
+ firestore_client: The Firestore database instance from which to query.
71
+ collection: The name of the Firestore collection to query.
72
+ vector_field: The name of the field containing the vector embeddings.
73
+ content_field: The name of the field containing the document content.
74
+ distance_measure: The distance measure to use when comparing vectors.
75
+ metadata_fields: Optional list of metadata fields to include.
59
76
  """
60
77
  self.ai = ai
61
78
  self.name = name
79
+ self.embedder = embedder
80
+ self.embedder_options = embedder_options
62
81
  self.firestore_client = firestore_client
63
82
  self.collection = collection
64
83
  self.vector_field = vector_field
65
84
  self.content_field = content_field
66
- self.embedder = embedder
67
- self.embedder_options = embedder_options
68
85
  self.distance_measure = distance_measure
69
86
  self.metadata_fields = metadata_fields
70
87
  self._validate_config()
71
88
 
72
- def _validate_config(self):
89
+ def _validate_config(self) -> None:
73
90
  """Validate the FirestoreRetriever configuration.
74
91
 
75
92
  Raises:
@@ -84,7 +101,7 @@ class FirestoreRetriever:
84
101
  if not self.firestore_client:
85
102
  raise ValueError('Firestore Retriever config must include firestore client.')
86
103
 
87
- def _to_content(self, doc_snapshot: DocumentSnapshot) -> list[dict[str, str]]:
104
+ def _to_content(self, doc_snapshot: DocumentSnapshot) -> list[DocumentPart]:
88
105
  """Convert a Firestore document snapshot to a list of content dictionaries.
89
106
 
90
107
  Args:
@@ -98,9 +115,9 @@ class FirestoreRetriever:
98
115
  return content_field(doc_snapshot)
99
116
  else:
100
117
  content = doc_snapshot.get(content_field)
101
- return [{'text': content}] if content else []
118
+ return [DocumentPart(root=TextPart(text=str(content)))] if content else []
102
119
 
103
- def _to_metadata(self, doc_snapshot: DocumentSnapshot) -> Document:
120
+ def _to_metadata(self, doc_snapshot: DocumentSnapshot) -> dict[str, object]:
104
121
  """Convert a Firestore document snapshot to a list of metadata dictionaries.
105
122
 
106
123
  Args:
@@ -109,17 +126,19 @@ class FirestoreRetriever:
109
126
  Returns:
110
127
  A list of dictionaries containing the metadata of the document.
111
128
  """
112
- metadata: dict[str, Any] = {}
129
+ metadata: dict[str, object] = {}
113
130
  metadata_fields = self.metadata_fields
114
131
  if metadata_fields:
115
132
  if callable(metadata_fields):
133
+ # pyrefly: ignore[bad-assignment] - MetadataTransformFn returns dict[str, Any]
116
134
  metadata = metadata_fields(doc_snapshot)
117
135
  else:
136
+ doc_dict = doc_snapshot.to_dict() or {}
118
137
  for field in metadata_fields:
119
- if field in doc_snapshot:
120
- metadata[field] = doc_snapshot.get(field)
138
+ if field in doc_dict:
139
+ metadata[field] = doc_dict[field]
121
140
  else:
122
- metadata = doc_snapshot.to_dict()
141
+ metadata = doc_snapshot.to_dict() or {}
123
142
  vector_field = self.vector_field
124
143
  content_field = self.content_field
125
144
  if vector_field in metadata:
@@ -148,17 +167,17 @@ class FirestoreRetriever:
148
167
  Returns:
149
168
  A RetrieverResponse Object containing retrieved documents
150
169
  """
151
- query = request.query
170
+ query = Document.from_document_data(document_data=request.query)
152
171
  query_embedding_result = await self.ai.embed(
153
172
  embedder=self.embedder,
154
- documents=[query],
173
+ content=query,
155
174
  options=self.embedder_options,
156
175
  )
157
176
 
158
- if not query_embedding_result.embeddings or len(query_embedding_result.embeddings) == 0:
177
+ if not query_embedding_result:
159
178
  raise GenkitError(message='Embedder returned no embeddings')
160
179
 
161
- query_embedding = query_embedding_result.embeddings[0].embedding
180
+ query_embedding = query_embedding_result[0].embedding
162
181
  query_vector = Vector(query_embedding)
163
182
  collection = self.firestore_client.collection(self.collection)
164
183
 
@@ -0,0 +1,113 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Tests for Firebase telemetry functionality."""
16
+
17
+ from unittest.mock import MagicMock, patch
18
+
19
+ from opentelemetry.sdk.trace import ReadableSpan
20
+
21
+ from genkit.plugins.firebase import add_firebase_telemetry
22
+ from genkit.plugins.google_cloud.telemetry.metrics import record_generate_metrics
23
+
24
+
25
+ def _create_model_span(
26
+ model_name: str = 'gemini-pro',
27
+ path: str = '/{myflow,t:flow}',
28
+ output: str = '{"usage": {"inputTokens": 100, "outputTokens": 50}}',
29
+ is_ok: bool = True,
30
+ start_time: int = 1000000000,
31
+ end_time: int = 1500000000,
32
+ ) -> MagicMock:
33
+ """Helper function to create a model action span for testing.
34
+
35
+ Args:
36
+ model_name: The model name for genkit:name attribute
37
+ path: The genkit:path value
38
+ output: The genkit:output JSON string
39
+ is_ok: Whether the span status is ok
40
+ start_time: Span start time in nanoseconds
41
+ end_time: Span end time in nanoseconds
42
+
43
+ Returns:
44
+ A mocked ReadableSpan with model action attributes
45
+ """
46
+ mock_span = MagicMock(spec=ReadableSpan)
47
+ mock_span.attributes = {
48
+ 'genkit:type': 'action',
49
+ 'genkit:metadata:subtype': 'model',
50
+ 'genkit:name': model_name,
51
+ 'genkit:path': path,
52
+ 'genkit:output': output,
53
+ }
54
+ mock_span.status.is_ok = is_ok
55
+ mock_span.start_time = start_time
56
+ mock_span.end_time = end_time
57
+ return mock_span
58
+
59
+
60
+ @patch('genkit.plugins.firebase.add_gcp_telemetry')
61
+ def test_firebase_telemetry_delegates_to_gcp(mock_add_gcp_telemetry: MagicMock) -> None:
62
+ """Test that Firebase telemetry delegates to GCP telemetry."""
63
+ add_firebase_telemetry()
64
+ mock_add_gcp_telemetry.assert_called_once_with(force_export=False)
65
+
66
+
67
+ @patch('genkit.plugins.google_cloud.telemetry.metrics._output_tokens')
68
+ @patch('genkit.plugins.google_cloud.telemetry.metrics._input_tokens')
69
+ @patch('genkit.plugins.google_cloud.telemetry.metrics._latency')
70
+ @patch('genkit.plugins.google_cloud.telemetry.metrics._failures')
71
+ @patch('genkit.plugins.google_cloud.telemetry.metrics._requests')
72
+ def test_record_generate_metrics_with_model_action(
73
+ mock_requests: MagicMock,
74
+ mock_failures: MagicMock,
75
+ mock_latency: MagicMock,
76
+ mock_input_tokens: MagicMock,
77
+ mock_output_tokens: MagicMock,
78
+ ) -> None:
79
+ """Test that metrics are recorded for model action spans with usage data."""
80
+ # Setup mocks
81
+ mock_request_counter = MagicMock()
82
+ mock_latency_histogram = MagicMock()
83
+ mock_input_counter = MagicMock()
84
+ mock_output_counter = MagicMock()
85
+
86
+ mock_requests.return_value = mock_request_counter
87
+ mock_failures.return_value = MagicMock()
88
+ mock_latency.return_value = mock_latency_histogram
89
+ mock_input_tokens.return_value = mock_input_counter
90
+ mock_output_tokens.return_value = mock_output_counter
91
+
92
+ # Create test span using helper
93
+ mock_span = _create_model_span(
94
+ model_name='gemini-pro',
95
+ path='/{myflow,t:flow}',
96
+ output='{"usage": {"inputTokens": 100, "outputTokens": 50}}',
97
+ )
98
+
99
+ # Execute
100
+ record_generate_metrics(mock_span)
101
+
102
+ # Verify dimensions
103
+ expected_dimensions = {'model': 'gemini-pro', 'source': 'myflow', 'error': 'none'}
104
+
105
+ # Verify requests counter
106
+ mock_request_counter.add.assert_called_once_with(1, expected_dimensions)
107
+
108
+ # Verify latency (500ms = 1.5s - 1.0s)
109
+ mock_latency_histogram.record.assert_called_once_with(500.0, expected_dimensions)
110
+
111
+ # Verify token counts
112
+ mock_input_counter.add.assert_called_once_with(100, expected_dimensions)
113
+ mock_output_counter.add.assert_called_once_with(50, expected_dimensions)
@@ -1,10 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genkit-plugin-firebase
3
- Version: 0.3.2
3
+ Version: 0.5.0
4
4
  Summary: Genkit Firebase Plugin
5
+ Project-URL: Bug Tracker, https://github.com/firebase/genkit/issues
6
+ Project-URL: Documentation, https://firebase.google.com/docs/genkit
7
+ Project-URL: Homepage, https://github.com/firebase/genkit
8
+ Project-URL: Repository, https://github.com/firebase/genkit/tree/main/py
5
9
  Author: Google
6
- License: Apache-2.0
10
+ License-Expression: Apache-2.0
7
11
  License-File: LICENSE
12
+ Keywords: ai,artificial-intelligence,firebase,firestore,generative-ai,genkit,google,llm,machine-learning,telemetry
8
13
  Classifier: Development Status :: 3 - Alpha
9
14
  Classifier: Environment :: Console
10
15
  Classifier: Environment :: Web Environment
@@ -17,8 +22,10 @@ Classifier: Programming Language :: Python :: 3.10
17
22
  Classifier: Programming Language :: Python :: 3.11
18
23
  Classifier: Programming Language :: Python :: 3.12
19
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
20
26
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
27
  Classifier: Topic :: Software Development :: Libraries
28
+ Classifier: Typing :: Typed
22
29
  Requires-Python: >=3.10
23
30
  Requires-Dist: genkit
24
31
  Requires-Dist: google-cloud-firestore
@@ -0,0 +1,10 @@
1
+ genkit/plugins/firebase/__init__.py,sha256=Lx8VqaFs4CCylHHF7kcgRmwLZ_2xLD7q2-vYUGb_1kM,14800
2
+ genkit/plugins/firebase/constant.py,sha256=wYFGr6O_Y2FJrBPAWsDojMeVXD_kvP1ZHLuRJqbpECU,826
3
+ genkit/plugins/firebase/firestore.py,sha256=oxtZLkrnbkcIjjHJLoQMq2UNhhHkV8J96cwk55JrPSU,3459
4
+ genkit/plugins/firebase/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ genkit/plugins/firebase/retriever.py,sha256=wy6IR3w0lYD3nImQ3bGiO-imYam5Ae2UTFnyXnQGMCI,8075
6
+ genkit/plugins/firebase/tests/telemetry_test.py,sha256=SDg9-Gih-aywPbk0g1U2GqQKj2ISdlwL6JpH84YsH_Q,4158
7
+ genkit_plugin_firebase-0.5.0.dist-info/METADATA,sha256=0pvfCiLqkb0uhmBkYVihg-oFvv1Hr9RBwgLHWxwi3DY,1623
8
+ genkit_plugin_firebase-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
9
+ genkit_plugin_firebase-0.5.0.dist-info/licenses/LICENSE,sha256=bsvE5_qSn_2LH2G-haMvT_AoIeINhX6fvzZTlyq2xJY,11340
10
+ genkit_plugin_firebase-0.5.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,13 +0,0 @@
1
- genkit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- genkit/plugins/firebase/__init__.py,sha256=-TqQ9fvRvo2GstGOGKtTelnyCodyHMcrjz8GFWvJaz4,874
3
- genkit/plugins/firebase/constant.py,sha256=wYFGr6O_Y2FJrBPAWsDojMeVXD_kvP1ZHLuRJqbpECU,826
4
- genkit/plugins/firebase/firestore.py,sha256=nWhoUMfgRZZvz5_nMpyiYmziUlSn_4ReaSxUe1cxih0,3831
5
- genkit/plugins/firebase/retriever.py,sha256=EOiVzU972gqvwRWWSb8wfHdylu3lxN_4FKtm-jfkgYA,6804
6
- genkit/plugins/firebase/__init__.py,sha256=-TqQ9fvRvo2GstGOGKtTelnyCodyHMcrjz8GFWvJaz4,874
7
- genkit/plugins/firebase/constant.py,sha256=wYFGr6O_Y2FJrBPAWsDojMeVXD_kvP1ZHLuRJqbpECU,826
8
- genkit/plugins/firebase/firestore.py,sha256=nWhoUMfgRZZvz5_nMpyiYmziUlSn_4ReaSxUe1cxih0,3831
9
- genkit/plugins/firebase/retriever.py,sha256=EOiVzU972gqvwRWWSb8wfHdylu3lxN_4FKtm-jfkgYA,6804
10
- genkit_plugin_firebase-0.3.2.dist-info/METADATA,sha256=sZbfsqXsKE7EamJXYfsyE69PfkxfFOh5dNfGHNTXpLM,1151
11
- genkit_plugin_firebase-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
- genkit_plugin_firebase-0.3.2.dist-info/licenses/LICENSE,sha256=bsvE5_qSn_2LH2G-haMvT_AoIeINhX6fvzZTlyq2xJY,11340
13
- genkit_plugin_firebase-0.3.2.dist-info/RECORD,,
File without changes