Skip to content

feat(firebase-ai): create ai package, vertexai wraps around it #8555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 64 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
0857b47
chore: initial cp over to ai directory
russellwheatley Jun 2, 2025
b4b9407
refactor: move to AI implementation, including AIModel base class
russellwheatley Jun 3, 2025
f4280ae
chore: update types for FirebaseApp to match JS SDK
russellwheatley Jun 3, 2025
c725a09
chore: update CHANGELOG & package.json
russellwheatley Jun 3, 2025
d6f4264
format
russellwheatley Jun 3, 2025
00f9990
request-helpers
russellwheatley Jun 3, 2025
492d9cb
request.ts
russellwheatley Jun 3, 2025
2b84bf5
response-helpers.ts
russellwheatley Jun 3, 2025
7a22950
schema-builder.ts
russellwheatley Jun 3, 2025
6402aa4
stream-reader.ts
russellwheatley Jun 3, 2025
0636826
chat-session-helpers.ts
russellwheatley Jun 3, 2025
d3ae723
chat-session.ts
russellwheatley Jun 3, 2025
01297c8
count-tokens.ts
russellwheatley Jun 3, 2025
c64c85c
generate-content.ts
russellwheatley Jun 3, 2025
97c713e
models index
russellwheatley Jun 3, 2025
8da0826
enums.ts
russellwheatley Jun 3, 2025
e6f54e6
error.ts
russellwheatley Jun 3, 2025
c12e76e
chore: add googleai to exports
russellwheatley Jun 3, 2025
f8d6ef6
request.ts types
russellwheatley Jun 3, 2025
3b98d54
types/responses.ts
russellwheatley Jun 3, 2025
e8cb7d3
types/schema.ts
russellwheatley Jun 3, 2025
9ef6afe
test: backend
russellwheatley Jun 3, 2025
81bcbab
add license header to test file
russellwheatley Jun 3, 2025
073db4b
test: googleai-mapper
russellwheatley Jun 4, 2025
a98ff8d
test: rename scripts and location to "ai"
russellwheatley Jun 4, 2025
152ed66
chore: firebase_ai yarn.lock
russellwheatley Jun 4, 2025
fd3cdf9
test(ai): update unit test for firebase ai
russellwheatley Jun 4, 2025
662183a
test: update convert mocks in line with latest mock response repo
russellwheatley Jun 4, 2025
15b4b99
test(ai): update script name to run
russellwheatley Jun 4, 2025
be07881
test(ai): getMockResponse()
russellwheatley Jun 4, 2025
0f8b8b2
test(ai): mock-response update for new mocks
russellwheatley Jun 4, 2025
b57874d
test(ai): count tokens unit tests
russellwheatley Jun 4, 2025
dd8782a
test: generate-content mock response
russellwheatley Jun 4, 2025
d8d5a52
test(ai): update unit tests to use updated mocks
russellwheatley Jun 4, 2025
b886279
test: fix unit tests
russellwheatley Jun 4, 2025
70df14a
test: fixed another unit test suite
russellwheatley Jun 4, 2025
5cfdb3c
test: add TS no-check to generated mocks
russellwheatley Jun 4, 2025
d3d06ab
refactor(vertexai): initial setup to use ai package
russellwheatley Jun 5, 2025
7b3b299
refactor: remove vertexai code and wrap around firebase ai package
russellwheatley Jun 5, 2025
223ed4e
chore: update script name
russellwheatley Jun 5, 2025
9072011
chore: firebaseerror from utils
russellwheatley Jun 5, 2025
9eeb3bb
chore: import vertex constant
russellwheatley Jun 5, 2025
fe24a9e
chore(vertexai): rm testing from vertex package
russellwheatley Jun 5, 2025
185a1d0
chore: update logger to ai
russellwheatley Jun 5, 2025
867a058
chore(vertexai): rm obsolete files
russellwheatley Jun 5, 2025
eae2fe8
chore(vertexai): revert back to prev. tsconfig
russellwheatley Jun 5, 2025
57bbaa8
chore(vertexai): symlink ai lib/ folder
russellwheatley Jun 5, 2025
dfd5991
chore(vertexai): wrap around ai
russellwheatley Jun 5, 2025
518c8f8
chore(vertexai): remove logger
russellwheatley Jun 5, 2025
cde4fae
test(vertexai): rm e2e tests
russellwheatley Jun 5, 2025
d53e7c7
refactor: make ai dependency on vertexai
russellwheatley Jun 6, 2025
3b082d0
test: fix test
russellwheatley Jun 6, 2025
e8781b2
fix: do not use RN URL to construct url
russellwheatley Jun 6, 2025
11cf91b
chore(ai): write example app for ai package
russellwheatley Jun 6, 2025
b1c952b
fix(ai): allow auth and app check to be passed in
russellwheatley Jun 6, 2025
520f848
chore: clean up of exports
russellwheatley Jun 6, 2025
6da0570
chore: rm mock script from vertex
russellwheatley Jun 6, 2025
2b51ccd
chore: update linter ignore list
russellwheatley Jun 6, 2025
ca4053b
docs(ai): write usage docs
russellwheatley Jun 6, 2025
e47cb97
format
russellwheatley Jun 6, 2025
1077ae5
rm note
russellwheatley Jun 6, 2025
097d8cf
scrub TODO
russellwheatley Jun 6, 2025
2ef02c0
Merge branch 'main' into firebase-ai
russellwheatley Jun 10, 2025
2dd4249
chore: fix yarn.lock
russellwheatley Jun 10, 2025
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
440 changes: 440 additions & 0 deletions docs/ai/usage/index.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ export default [
'**/app.playground.js',
'**/type-test.ts',
'packages/**/modular/dist/**/*',
'packages/vertexai/__tests__/test-utils',
'packages/ai/__tests__/test-utils',
'packages/vertexai/dist',
'packages/ai/dist',
],
},
...compat
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"lint:spellcheck": "spellchecker --quiet --files=\"docs/**/*.md\" --dictionaries=\"./.spellcheck.dict.txt\" --reports=\"spelling.json\" --plugins spell indefinite-article repeated-words syntax-mentions syntax-urls frontmatter",
"tsc:compile": "tsc --project .",
"lint:all": "yarn lint && yarn lint:markdown && yarn lint:spellcheck && yarn tsc:compile",
"tests:vertex:mocks": "./scripts/vertex_mock_responses.sh && yarn ts-node ./packages/vertexai/__tests__/test-utils/convert-mocks.ts",
"tests:ai:mocks": "./scripts/ai_mock_responses.sh && yarn ts-node ./packages/ai/__tests__/test-utils/convert-mocks.ts",
"tests:jest": "jest",
"tests:jest-watch": "jest --watch",
"tests:jest-coverage": "jest --coverage",
Expand Down
12 changes: 12 additions & 0 deletions packages/ai/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## Feature

Initial release of the Firebase AI Logic SDK (`FirebaseAI`). This SDK *replaces* the previous Vertex AI in Firebase SDK (`FirebaseVertexAI`) to accommodate the evolving set of supported features and services.
The new Firebase AI Logic SDK provides **preview** support for the Gemini Developer API, including its free tier offering.
Using the Firebase AI Logic SDK with the Vertex AI Gemini API is still generally available (GA).

To start using the new SDK, import the `@react-native-firebase/ai` package and use the modular method `getAI()` to initialize. See details in the [migration guide](https://firebase.google.com/docs/vertex-ai/migrate-to-latest-sdk).
32 changes: 32 additions & 0 deletions packages/ai/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Apache-2.0 License
------------------

Copyright (c) 2016-present Invertase Limited <oss@invertase.io> & Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this library except in compliance with the License.

You may obtain a copy of the Apache-2.0 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.


Creative Commons Attribution 3.0 License
----------------------------------------

Copyright (c) 2016-present Invertase Limited <oss@invertase.io> & Contributors

Documentation and other instructional materials provided for this project
(including on a separate documentation repository or it's documentation website) are
licensed under the Creative Commons Attribution 3.0 License. Code samples/blocks
contained therein are licensed under the Apache License, Version 2.0 (the "License"), as above.

You may obtain a copy of the Creative Commons Attribution 3.0 License at

https://creativecommons.org/licenses/by/3.0/
55 changes: 55 additions & 0 deletions packages/ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<p align="center">
<a href="https://rnfirebase.io">
<img width="160px" src="https://i.imgur.com/JIyBtKW.png"><br/>
</a>
<h2 align="center">React Native Firebase - AI Logic</h2>
</p>

<p align="center">
<a href="https://api.rnfirebase.io/coverage/ai/detail"><img src="https://api.rnfirebase.io/coverage/ai/badge?style=flat-square" alt="Coverage"></a>
<a href="https://www.npmjs.com/package/@react-native-firebase/ai"><img src="https://img.shields.io/npm/dm/@react-native-firebase/ai.svg?style=flat-square" alt="NPM downloads"></a>
<a href="https://www.npmjs.com/package/@react-native-firebase/ai"><img src="https://img.shields.io/npm/v/@react-native-firebase/ai.svg?style=flat-square" alt="NPM version"></a>
<a href="/LICENSE"><img src="https://img.shields.io/npm/l/react-native-firebase.svg?style=flat-square" alt="License"></a>
<a href="https://lerna.js.org/"><img src="https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg?style=flat-square" alt="Maintained with Lerna"></a>
</p>

<p align="center">
<a href="https://invertase.link/discord"><img src="https://img.shields.io/discord/295953187817521152.svg?style=flat-square&colorA=7289da&label=Chat%20on%20Discord" alt="Chat on Discord"></a>
<a href="https://twitter.com/rnfirebase"><img src="https://img.shields.io/twitter/follow/rnfirebase.svg?style=flat-square&colorA=1da1f2&colorB=&label=Follow%20on%20Twitter" alt="Follow on Twitter"></a>
<a href="https://www.facebook.com/groups/rnfirebase"><img src="https://img.shields.io/badge/Follow%20on%20Facebook-4172B8?logo=facebook&style=flat-square&logoColor=fff" alt="Follow on Facebook"></a>
</p>

---

Firebase AI Logic gives you access to the latest generative AI models from Google.

If you need to call the Gemini API directly from your mobile or web app — rather than server-side — you can use the Firebase AI Logic client SDKs. These client SDKs are built specifically for use with mobile and web apps, offering security options against unauthorized clients as well as integrations with other Firebase services.

[> Learn More](https://firebase.google.com/docs/ai-logic/)

## Installation

Requires `@react-native-firebase/app` to be installed.

```bash
yarn add @react-native-firebase/ai
```

## Documentation

- [Quick Start](https://rnfirebase.io/ai/usage)

## License

- See [LICENSE](/LICENSE)

---

<p>
<img align="left" width="75px" src="https://static.invertase.io/assets/invertase-logo-small.png">
<p align="left">
Built and maintained with 💛 by <a href="https://invertase.io">Invertase</a>.
</p>
</p>

---
112 changes: 112 additions & 0 deletions packages/ai/__tests__/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* @license
* Copyright 2024 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 { describe, expect, it } from '@jest/globals';
import { type ReactNativeFirebase } from '../../app/lib';

import { ModelParams, AIErrorCode } from '../lib/types';
import { AIError } from '../lib/errors';
import { getGenerativeModel } from '../lib/index';

import { AI } from '../lib/public-types';
import { GenerativeModel } from '../lib/models/generative-model';

import { AI_TYPE } from '../lib/constants';
import { VertexAIBackend } from '../lib/backend';

const fakeAI: AI = {
app: {
name: 'DEFAULT',
options: {
apiKey: 'key',
appId: 'appId',
projectId: 'my-project',
},
} as ReactNativeFirebase.FirebaseApp,
backend: new VertexAIBackend('us-central1'),
location: 'us-central1',
};

describe('Top level API', () => {
it('getGenerativeModel throws if no model is provided', () => {
try {
getGenerativeModel(fakeAI, {} as ModelParams);
} catch (e) {
expect((e as AIError).code).toContain(AIErrorCode.NO_MODEL);
expect((e as AIError).message).toContain(
`AI: Must provide a model name. Example: ` +
`getGenerativeModel({ model: 'my-model-name' }) (${AI_TYPE}/${AIErrorCode.NO_MODEL})`,
);
}
});

it('getGenerativeModel throws if no apiKey is provided', () => {
const fakeVertexNoApiKey = {
...fakeAI,
app: { options: { projectId: 'my-project', appId: 'my-appid' } },
} as AI;
try {
getGenerativeModel(fakeVertexNoApiKey, { model: 'my-model' });
} catch (e) {
expect((e as AIError).code).toContain(AIErrorCode.NO_API_KEY);
expect((e as AIError).message).toBe(
`AI: The "apiKey" field is empty in the local ` +
`Firebase config. Firebase AI requires this field to` +
` contain a valid API key. (${AI_TYPE}/${AIErrorCode.NO_API_KEY})`,
);
}
});

it('getGenerativeModel throws if no projectId is provided', () => {
const fakeVertexNoProject = {
...fakeAI,
app: { options: { apiKey: 'my-key' } },
} as AI;
try {
getGenerativeModel(fakeVertexNoProject, { model: 'my-model' });
} catch (e) {
expect((e as AIError).code).toContain(AIErrorCode.NO_PROJECT_ID);
expect((e as AIError).message).toBe(
`AI: The "projectId" field is empty in the local` +
` Firebase config. Firebase AI requires this field ` +
`to contain a valid project ID. (${AI_TYPE}/${AIErrorCode.NO_PROJECT_ID})`,
);
}
});

it('getGenerativeModel throws if no appId is provided', () => {
const fakeVertexNoProject = {
...fakeAI,
app: { options: { apiKey: 'my-key', projectId: 'my-projectid' } },
} as AI;
try {
getGenerativeModel(fakeVertexNoProject, { model: 'my-model' });
} catch (e) {
expect((e as AIError).code).toContain(AIErrorCode.NO_APP_ID);
expect((e as AIError).message).toBe(
`AI: The "appId" field is empty in the local` +
` Firebase config. Firebase AI requires this field ` +
`to contain a valid app ID. (${AI_TYPE}/${AIErrorCode.NO_APP_ID})`,
);
}
});

it('getGenerativeModel gets a GenerativeModel', () => {
const genModel = getGenerativeModel(fakeAI, { model: 'my-model' });
expect(genModel).toBeInstanceOf(GenerativeModel);
expect(genModel.model).toBe('publishers/google/models/my-model');
});
});
55 changes: 55 additions & 0 deletions packages/ai/__tests__/backend.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @license
* Copyright 2024 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 { describe, it, expect } from '@jest/globals';
import { GoogleAIBackend, VertexAIBackend } from '../lib/backend';
import { BackendType } from '../lib/public-types';
import { DEFAULT_LOCATION } from '../lib/constants';

describe('Backend', () => {
describe('GoogleAIBackend', () => {
it('sets backendType to GOOGLE_AI', () => {
const backend = new GoogleAIBackend();
expect(backend.backendType).toBe(BackendType.GOOGLE_AI);
});
});

describe('VertexAIBackend', () => {
it('set backendType to VERTEX_AI', () => {
const backend = new VertexAIBackend();
expect(backend.backendType).toBe(BackendType.VERTEX_AI);
expect(backend.location).toBe(DEFAULT_LOCATION);
});

it('sets custom location', () => {
const backend = new VertexAIBackend('test-location');
expect(backend.backendType).toBe(BackendType.VERTEX_AI);
expect(backend.location).toBe('test-location');
});

it('uses default location if location is empty string', () => {
const backend = new VertexAIBackend('');
expect(backend.backendType).toBe(BackendType.VERTEX_AI);
expect(backend.location).toBe(DEFAULT_LOCATION);
});

it('uses default location if location is null', () => {
const backend = new VertexAIBackend(null as any);
expect(backend.backendType).toBe(BackendType.VERTEX_AI);
expect(backend.location).toBe(DEFAULT_LOCATION);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import { GenerateContentStreamResult } from '../lib/types';
import { ChatSession } from '../lib/methods/chat-session';
import { ApiSettings } from '../lib/types/internal';
import { RequestOptions } from '../lib/types/requests';
import { VertexAIBackend } from '../lib/backend';

const fakeApiSettings: ApiSettings = {
apiKey: 'key',
project: 'my-project',
appId: 'my-appid',
location: 'us-central1',
backend: new VertexAIBackend(),
};

const requestOptions: RequestOptions = {
Expand Down
Loading
Loading