From 556c3489fe57b69547c99faa2825322dae6b25be Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Mon, 24 Mar 2025 14:12:35 -0700 Subject: [PATCH 01/28] Define HybridParams --- common/api-review/vertexai.api.md | 24 +++++++++++++++++++++++- packages/vertexai/src/api.ts | 18 +++++++++++++++--- packages/vertexai/src/types/ai.ts | 21 +++++++++++++++++++++ packages/vertexai/src/types/enums.ts | 10 ++++++++++ packages/vertexai/src/types/requests.ts | 14 +++++++++++++- 5 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 packages/vertexai/src/types/ai.ts diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index e7f00c2f4e0..287e2490788 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -344,7 +344,7 @@ export class GenerativeModel extends VertexAIModel { } // @public -export function getGenerativeModel(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: RequestOptions): GenerativeModel; +export function getGenerativeModel(vertexAI: VertexAI, onCloudOrHybridParams: ModelParams | HybridParams, requestOptions?: RequestOptions): GenerativeModel; // @beta export function getImagenModel(vertexAI: VertexAI, modelParams: ImagenModelParams, requestOptions?: RequestOptions): ImagenModel; @@ -500,6 +500,28 @@ export interface ImagenSafetySettings { safetyFilterLevel?: ImagenSafetyFilterLevel; } +// @public +export interface HybridParams { + // (undocumented) + mode?: InferenceMode; + // (undocumented) + onCloudParams?: ModelParams; + // Warning: (ae-forgotten-export) The symbol "AILanguageModelCreateOptionsWithSystemPrompt" needs to be exported by the entry point index.d.ts + // + // (undocumented) + onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; +} + +// @public +export enum InferenceMode { + // (undocumented) + ONLY_ON_CLOUD = "ONLY_ON_CLOUD", + // (undocumented) + ONLY_ON_DEVICE = "ONLY_ON_DEVICE", + // (undocumented) + PREFER_ON_DEVICE = "PREFER_ON_DEVICE" +} + // @public export interface InlineDataPart { // (undocumented) diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 7843a5bdeee..323cfd10e80 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -23,6 +23,7 @@ import { VertexAIService } from './service'; import { VertexAI, VertexAIOptions } from './public-types'; import { ImagenModelParams, + HybridParams, ModelParams, RequestOptions, VertexAIErrorCode @@ -70,16 +71,27 @@ export function getVertexAI( */ export function getGenerativeModel( vertexAI: VertexAI, - modelParams: ModelParams, + onCloudOrHybridParams: ModelParams | HybridParams, requestOptions?: RequestOptions ): GenerativeModel { - if (!modelParams.model) { + // Disambiguates onCloudOrHybridParams input. + const hybridParams = onCloudOrHybridParams as HybridParams; + let onCloudParams: ModelParams; + if (hybridParams.mode) { + onCloudParams = hybridParams.onCloudParams || { + model: 'gemini-2.0-flash-lite' + }; + } else { + onCloudParams = onCloudOrHybridParams as ModelParams; + } + + if (!onCloudParams.model) { throw new VertexAIError( VertexAIErrorCode.NO_MODEL, `Must provide a model name. Example: getGenerativeModel({ model: 'my-model-name' })` ); } - return new GenerativeModel(vertexAI, modelParams, requestOptions); + return new GenerativeModel(vertexAI, onCloudParams, requestOptions); } /** diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts new file mode 100644 index 00000000000..30b20863373 --- /dev/null +++ b/packages/vertexai/src/types/ai.ts @@ -0,0 +1,21 @@ +/** + * Shims @types/dom-chromium-ai + * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. + */ +interface AILanguageModelCreateOptions { + topK?: number; + temperature?: number; +} + +export interface AILanguageModelCreateOptionsWithSystemPrompt + extends AILanguageModelCreateOptions { + systemPrompt?: string; + initialPrompts?: AILanguageModelPrompt[]; +} + +type AILanguageModelPromptRole = 'user' | 'assistant'; + +interface AILanguageModelPrompt { + role: AILanguageModelPromptRole; + content: string; +} diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index a9481d40f5f..1f81ed79a8f 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -240,3 +240,13 @@ export enum Modality { */ DOCUMENT = 'DOCUMENT' } + +/** + * Determines whether inference happens on-device or on-cloud. + * @public + */ +export enum InferenceMode { + PREFER_ON_DEVICE = 'PREFER_ON_DEVICE', + ONLY_ON_DEVICE = 'ONLY_ON_DEVICE', + ONLY_ON_CLOUD = 'ONLY_ON_CLOUD' +} diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index c15258b06d0..548e53ee686 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -16,12 +16,14 @@ */ import { TypedSchema } from '../requests/schema-builder'; +import { AILanguageModelCreateOptionsWithSystemPrompt } from './ai'; import { Content, Part } from './content'; import { FunctionCallingMode, HarmBlockMethod, HarmBlockThreshold, - HarmCategory + HarmCategory, + InferenceMode } from './enums'; import { ObjectSchemaInterface, SchemaRequest } from './schema'; @@ -213,3 +215,13 @@ export interface FunctionCallingConfig { mode?: FunctionCallingMode; allowedFunctionNames?: string[]; } + +/** + * Configures on-device and on-cloud inference. + * @public + */ +export interface HybridParams { + mode?: InferenceMode; + onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; + onCloudParams?: ModelParams; +} From 272ff16c3a6eb64425c84e5a84dc35128a09e05b Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Mon, 24 Mar 2025 16:25:35 -0700 Subject: [PATCH 02/28] Copy over most types from @types package --- packages/vertexai/src/types/ai.ts | 378 +++++++++++++++++++++++++++++- 1 file changed, 369 insertions(+), 9 deletions(-) diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts index 30b20863373..86ce44b4d98 100644 --- a/packages/vertexai/src/types/ai.ts +++ b/packages/vertexai/src/types/ai.ts @@ -2,20 +2,380 @@ * Shims @types/dom-chromium-ai * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. */ +interface AI { + readonly languageModel: AILanguageModelFactory; + readonly summarizer: AISummarizerFactory; + readonly writer: AIWriterFactory; + readonly rewriter: AIRewriterFactory; + readonly translator: AITranslatorFactory; + readonly languageDetector: AILanguageDetectorFactory; +} + +interface AICreateMonitor extends EventTarget { + ondownloadprogress: ((this: AICreateMonitor, ev: DownloadProgressEvent) => any) | null; + + addEventListener( + type: K, + listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +interface DownloadProgressEvent extends Event { + readonly loaded: number; + readonly total: number; +} + +interface AICreateMonitorEventMap { + downloadprogress: DownloadProgressEvent; +} + +type AICreateMonitorCallback = (monitor: AICreateMonitor) => void; + +type AICapabilityAvailability = "readily" | "after-download" | "no"; + +// Language Model +// https://github.com/explainers-by-googlers/prompt-api/#full-api-surface-in-web-idl + +interface AILanguageModelFactory { + create( + options?: AILanguageModelCreateOptionsWithSystemPrompt | AILanguageModelCreateOptionsWithoutSystemPrompt, + ): Promise; + capabilities(): Promise; +} + interface AILanguageModelCreateOptions { - topK?: number; - temperature?: number; + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + topK?: number; + temperature?: number; } -export interface AILanguageModelCreateOptionsWithSystemPrompt - extends AILanguageModelCreateOptions { - systemPrompt?: string; - initialPrompts?: AILanguageModelPrompt[]; +export interface AILanguageModelCreateOptionsWithSystemPrompt extends AILanguageModelCreateOptions { + systemPrompt?: string; + initialPrompts?: AILanguageModelPrompt[]; } -type AILanguageModelPromptRole = 'user' | 'assistant'; +interface AILanguageModelCreateOptionsWithoutSystemPrompt extends AILanguageModelCreateOptions { + systemPrompt?: never; + initialPrompts?: + | [AILanguageModelSystemPrompt, ...AILanguageModelPrompt[]] + | AILanguageModelPrompt[]; +} + +type AILanguageModelPromptRole = "user" | "assistant"; +type AILanguageModelInitialPromptRole = "system" | AILanguageModelPromptRole; interface AILanguageModelPrompt { - role: AILanguageModelPromptRole; - content: string; + role: AILanguageModelPromptRole; + content: string; +} + +interface AILanguageModelInitialPrompt { + role: AILanguageModelInitialPromptRole; + content: string; +} + +interface AILanguageModelSystemPrompt extends AILanguageModelInitialPrompt { + role: "system"; +} + +type AILanguageModelPromptInput = string | AILanguageModelPrompt | AILanguageModelPrompt[]; + +interface AILanguageModel extends EventTarget { + prompt(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; + promptStreaming(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): ReadableStream; + + countPromptTokens(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; + readonly maxTokens: number; + readonly tokensSoFar: number; + readonly tokensLeft: number; + + readonly topK: number; + readonly temperature: number; + + oncontextoverflow: ((this: AILanguageModel, ev: Event) => any) | null; + + addEventListener( + type: K, + listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; + + clone(options?: AILanguageModelCloneOptions): Promise; + destroy(): void; +} + +interface AILanguageModelEventMap { + contextoverflow: Event; +} + +interface AILanguageModelPromptOptions { + signal?: AbortSignal; +} + +interface AILanguageModelCloneOptions { + signal?: AbortSignal; +} + +interface AILanguageModelCapabilities { + readonly available: AICapabilityAvailability; + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; + + readonly defaultTopK: number | null; + readonly maxTopK: number | null; + readonly defaultTemperature: number | null; + readonly maxTemperature: number | null; +} + +// Summarizer +// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl + +interface AISummarizerFactory { + create(options?: AISummarizerCreateOptions): Promise; + capabilities(): Promise; +} + +interface AISummarizerCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + sharedContext?: string; + type?: AISummarizerType; + format?: AISummarizerFormat; + length?: AISummarizerLength; +} + +type AISummarizerType = "tl;dr" | "key-points" | "teaser" | "headline"; +type AISummarizerFormat = "plain-text" | "markdown"; +type AISummarizerLength = "short" | "medium" | "long"; + +interface AISummarizer { + summarize(input: string, options?: AISummarizerSummarizeOptions): Promise; + summarizeStreaming(input: string, options?: AISummarizerSummarizeOptions): ReadableStream; + + readonly sharedContext: string; + readonly type: AISummarizerType; + readonly format: AISummarizerFormat; + readonly length: AISummarizerLength; + + destroy(): void; +} + +interface AISummarizerSummarizeOptions { + signal?: AbortSignal; + context?: string; +} + +interface AISummarizerCapabilities { + readonly available: AICapabilityAvailability; + + supportsType(type: AISummarizerType): AICapabilityAvailability; + supportsFormat(format: AISummarizerFormat): AICapabilityAvailability; + supportsLength(length: AISummarizerLength): AICapabilityAvailability; + + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; +} + +// Writer +// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl + +interface AIWriterFactory { + create(options?: AIWriterCreateOptions): Promise; + capabilities(): Promise; +} + +interface AIWriterCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + sharedContext?: string; + tone?: AIWriterTone; + format?: AIWriterFormat; + length?: AIWriterLength; +} + +type AIWriterTone = "formal" | "neutral" | "casual"; +type AIWriterFormat = "plain-text" | "markdown"; +type AIWriterLength = "short" | "medium" | "long"; + +interface AIWriter { + write(writingTask: string, options?: AIWriterWriteOptions): Promise; + writeStreaming(writingTask: string, options?: AIWriterWriteOptions): ReadableStream; + + readonly sharedContext: string; + readonly tone: AIWriterTone; + readonly format: AIWriterFormat; + readonly length: AIWriterLength; + + destroy(): void; +} + +interface AIWriterWriteOptions { + signal?: AbortSignal; + context?: string; +} + +interface AIWriterCapabilities { + readonly available: AICapabilityAvailability; + + supportsTone(tone: AIWriterTone): AICapabilityAvailability; + supportsFormat(format: AIWriterFormat): AICapabilityAvailability; + supportsLength(length: AIWriterLength): AICapabilityAvailability; + + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; +} + +// Rewriter +// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl + +interface AIRewriterFactory { + create(options?: AIRewriterCreateOptions): Promise; + capabilities(): Promise; +} + +interface AIRewriterCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + sharedContext?: string; + tone?: AIRewriterTone; + format?: AIRewriterFormat; + length?: AIRewriterLength; +} + +type AIRewriterTone = "as-is" | "more-formal" | "more-casual"; +type AIRewriterFormat = "as-is" | "plain-text" | "markdown"; +type AIRewriterLength = "as-is" | "shorter" | "longer"; + +interface AIRewriter { + rewrite(input: string, options?: AIRewriterRewriteOptions): Promise; + rewriteStreaming(input: string, options?: AIRewriterRewriteOptions): ReadableStream; + + readonly sharedContext: string; + readonly tone: AIRewriterTone; + readonly format: AIRewriterFormat; + readonly length: AIRewriterLength; + + destroy(): void; +} + +interface AIRewriterRewriteOptions { + signal?: AbortSignal; + context?: string; +} + +interface AIRewriterCapabilities { + readonly available: AICapabilityAvailability; + + supportsTone(tone: AIRewriterTone): AICapabilityAvailability; + supportsFormat(format: AIRewriterFormat): AICapabilityAvailability; + supportsLength(length: AIRewriterLength): AICapabilityAvailability; + + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; } + +// Translator +// https://github.com/WICG/translation-api?tab=readme-ov-file#full-api-surface-in-web-idl + +interface AITranslatorFactory { + create(options: AITranslatorCreateOptions): Promise; + capabilities(): Promise; +} + +interface AITranslator { + translate(input: string, options?: AITranslatorTranslateOptions): Promise; + translateStreaming(input: string, options?: AITranslatorTranslateOptions): ReadableStream; + + readonly sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier; + readonly targetLanguage: Intl.UnicodeBCP47LocaleIdentifier; + + destroy(): void; +} + +interface AITranslatorCapabilities { + readonly available: AICapabilityAvailability; + + languagePairAvailable( + sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier, + targetLanguage: Intl.UnicodeBCP47LocaleIdentifier, + ): AICapabilityAvailability; +} + +interface AITranslatorCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier; + targetLanguage: Intl.UnicodeBCP47LocaleIdentifier; +} + +interface AITranslatorTranslateOptions { + signal?: AbortSignal; +} + +// Language detector +// https://github.com/WICG/translation-api?tab=readme-ov-file#full-api-surface-in-web-idl + +interface AILanguageDetectorFactory { + create(options?: AILanguageDetectorCreateOptions): Promise; + capabilities(): Promise; +} + +interface AILanguageDetector { + detect(input: string, options?: AILanguageDetectorDetectOptions): Promise; + + destroy(): void; +} + +interface AILanguageDetectorCapabilities { + readonly available: AICapabilityAvailability; + + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; +} + +interface AILanguageDetectorCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; +} + +interface AILanguageDetectorDetectOptions { + signal?: AbortSignal; +} + +interface LanguageDetectionResult { + /** null represents unknown language */ + detectedLanguage: Intl.UnicodeBCP47LocaleIdentifier | null; + confidence: number; +} \ No newline at end of file From aa9c4f0340c606c58a35cd8f71b1f1e82f341a13 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Mon, 24 Mar 2025 16:34:36 -0700 Subject: [PATCH 03/28] Document HybridParams and InferenceMode --- common/api-review/vertexai.api.md | 4 ---- packages/vertexai/src/types/enums.ts | 3 +++ packages/vertexai/src/types/requests.ts | 9 +++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 287e2490788..46d247853a5 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -502,13 +502,9 @@ export interface ImagenSafetySettings { // @public export interface HybridParams { - // (undocumented) mode?: InferenceMode; - // (undocumented) onCloudParams?: ModelParams; // Warning: (ae-forgotten-export) The symbol "AILanguageModelCreateOptionsWithSystemPrompt" needs to be exported by the entry point index.d.ts - // - // (undocumented) onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; } diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index 1f81ed79a8f..f9eddc564f8 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -246,7 +246,10 @@ export enum Modality { * @public */ export enum InferenceMode { + // Specifies the SDK should use on-device if possible, or fall back to on-cloud. PREFER_ON_DEVICE = 'PREFER_ON_DEVICE', + // Specifies the SDK must use on-device or throw. ONLY_ON_DEVICE = 'ONLY_ON_DEVICE', + // Specifies the SDK must use on-cloud. ONLY_ON_CLOUD = 'ONLY_ON_CLOUD' } diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 548e53ee686..9b01c7efd65 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -221,7 +221,16 @@ export interface FunctionCallingConfig { * @public */ export interface HybridParams { + /** + * Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. + */ mode?: InferenceMode; + /** + * Optional. Specifies advanced params for on-device inference + */ onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; + /** + * Optional. Specifies advanced params for on-cloud inference. + */ onCloudParams?: ModelParams; } From 12e07c06ea0e0b5437874449314dde369d29291d Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 25 Mar 2025 09:08:29 -0700 Subject: [PATCH 04/28] Trim unused AI types --- packages/vertexai/src/types/ai.ts | 322 +----------------------------- 1 file changed, 3 insertions(+), 319 deletions(-) diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts index 86ce44b4d98..10cce1cab9b 100644 --- a/packages/vertexai/src/types/ai.ts +++ b/packages/vertexai/src/types/ai.ts @@ -2,20 +2,13 @@ * Shims @types/dom-chromium-ai * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. */ -interface AI { - readonly languageModel: AILanguageModelFactory; - readonly summarizer: AISummarizerFactory; - readonly writer: AIWriterFactory; - readonly rewriter: AIRewriterFactory; - readonly translator: AITranslatorFactory; - readonly languageDetector: AILanguageDetectorFactory; -} - interface AICreateMonitor extends EventTarget { + // eslint-disable-next-line @typescript-eslint/no-explicit-any ondownloadprogress: ((this: AICreateMonitor, ev: DownloadProgressEvent) => any) | null; addEventListener( type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, options?: boolean | AddEventListenerOptions, ): void; @@ -26,6 +19,7 @@ interface AICreateMonitor extends EventTarget { ): void; removeEventListener( type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, options?: boolean | EventListenerOptions, ): void; @@ -47,18 +41,9 @@ interface AICreateMonitorEventMap { type AICreateMonitorCallback = (monitor: AICreateMonitor) => void; -type AICapabilityAvailability = "readily" | "after-download" | "no"; - // Language Model // https://github.com/explainers-by-googlers/prompt-api/#full-api-surface-in-web-idl -interface AILanguageModelFactory { - create( - options?: AILanguageModelCreateOptionsWithSystemPrompt | AILanguageModelCreateOptionsWithoutSystemPrompt, - ): Promise; - capabilities(): Promise; -} - interface AILanguageModelCreateOptions { signal?: AbortSignal; monitor?: AICreateMonitorCallback; @@ -72,310 +57,9 @@ export interface AILanguageModelCreateOptionsWithSystemPrompt extends AILanguage initialPrompts?: AILanguageModelPrompt[]; } -interface AILanguageModelCreateOptionsWithoutSystemPrompt extends AILanguageModelCreateOptions { - systemPrompt?: never; - initialPrompts?: - | [AILanguageModelSystemPrompt, ...AILanguageModelPrompt[]] - | AILanguageModelPrompt[]; -} - type AILanguageModelPromptRole = "user" | "assistant"; -type AILanguageModelInitialPromptRole = "system" | AILanguageModelPromptRole; interface AILanguageModelPrompt { role: AILanguageModelPromptRole; content: string; } - -interface AILanguageModelInitialPrompt { - role: AILanguageModelInitialPromptRole; - content: string; -} - -interface AILanguageModelSystemPrompt extends AILanguageModelInitialPrompt { - role: "system"; -} - -type AILanguageModelPromptInput = string | AILanguageModelPrompt | AILanguageModelPrompt[]; - -interface AILanguageModel extends EventTarget { - prompt(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; - promptStreaming(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): ReadableStream; - - countPromptTokens(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; - readonly maxTokens: number; - readonly tokensSoFar: number; - readonly tokensLeft: number; - - readonly topK: number; - readonly temperature: number; - - oncontextoverflow: ((this: AILanguageModel, ev: Event) => any) | null; - - addEventListener( - type: K, - listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, - options?: boolean | AddEventListenerOptions, - ): void; - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | AddEventListenerOptions, - ): void; - removeEventListener( - type: K, - listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; - - clone(options?: AILanguageModelCloneOptions): Promise; - destroy(): void; -} - -interface AILanguageModelEventMap { - contextoverflow: Event; -} - -interface AILanguageModelPromptOptions { - signal?: AbortSignal; -} - -interface AILanguageModelCloneOptions { - signal?: AbortSignal; -} - -interface AILanguageModelCapabilities { - readonly available: AICapabilityAvailability; - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; - - readonly defaultTopK: number | null; - readonly maxTopK: number | null; - readonly defaultTemperature: number | null; - readonly maxTemperature: number | null; -} - -// Summarizer -// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl - -interface AISummarizerFactory { - create(options?: AISummarizerCreateOptions): Promise; - capabilities(): Promise; -} - -interface AISummarizerCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - sharedContext?: string; - type?: AISummarizerType; - format?: AISummarizerFormat; - length?: AISummarizerLength; -} - -type AISummarizerType = "tl;dr" | "key-points" | "teaser" | "headline"; -type AISummarizerFormat = "plain-text" | "markdown"; -type AISummarizerLength = "short" | "medium" | "long"; - -interface AISummarizer { - summarize(input: string, options?: AISummarizerSummarizeOptions): Promise; - summarizeStreaming(input: string, options?: AISummarizerSummarizeOptions): ReadableStream; - - readonly sharedContext: string; - readonly type: AISummarizerType; - readonly format: AISummarizerFormat; - readonly length: AISummarizerLength; - - destroy(): void; -} - -interface AISummarizerSummarizeOptions { - signal?: AbortSignal; - context?: string; -} - -interface AISummarizerCapabilities { - readonly available: AICapabilityAvailability; - - supportsType(type: AISummarizerType): AICapabilityAvailability; - supportsFormat(format: AISummarizerFormat): AICapabilityAvailability; - supportsLength(length: AISummarizerLength): AICapabilityAvailability; - - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; -} - -// Writer -// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl - -interface AIWriterFactory { - create(options?: AIWriterCreateOptions): Promise; - capabilities(): Promise; -} - -interface AIWriterCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - sharedContext?: string; - tone?: AIWriterTone; - format?: AIWriterFormat; - length?: AIWriterLength; -} - -type AIWriterTone = "formal" | "neutral" | "casual"; -type AIWriterFormat = "plain-text" | "markdown"; -type AIWriterLength = "short" | "medium" | "long"; - -interface AIWriter { - write(writingTask: string, options?: AIWriterWriteOptions): Promise; - writeStreaming(writingTask: string, options?: AIWriterWriteOptions): ReadableStream; - - readonly sharedContext: string; - readonly tone: AIWriterTone; - readonly format: AIWriterFormat; - readonly length: AIWriterLength; - - destroy(): void; -} - -interface AIWriterWriteOptions { - signal?: AbortSignal; - context?: string; -} - -interface AIWriterCapabilities { - readonly available: AICapabilityAvailability; - - supportsTone(tone: AIWriterTone): AICapabilityAvailability; - supportsFormat(format: AIWriterFormat): AICapabilityAvailability; - supportsLength(length: AIWriterLength): AICapabilityAvailability; - - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; -} - -// Rewriter -// https://github.com/explainers-by-googlers/writing-assistance-apis/#full-api-surface-in-web-idl - -interface AIRewriterFactory { - create(options?: AIRewriterCreateOptions): Promise; - capabilities(): Promise; -} - -interface AIRewriterCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - sharedContext?: string; - tone?: AIRewriterTone; - format?: AIRewriterFormat; - length?: AIRewriterLength; -} - -type AIRewriterTone = "as-is" | "more-formal" | "more-casual"; -type AIRewriterFormat = "as-is" | "plain-text" | "markdown"; -type AIRewriterLength = "as-is" | "shorter" | "longer"; - -interface AIRewriter { - rewrite(input: string, options?: AIRewriterRewriteOptions): Promise; - rewriteStreaming(input: string, options?: AIRewriterRewriteOptions): ReadableStream; - - readonly sharedContext: string; - readonly tone: AIRewriterTone; - readonly format: AIRewriterFormat; - readonly length: AIRewriterLength; - - destroy(): void; -} - -interface AIRewriterRewriteOptions { - signal?: AbortSignal; - context?: string; -} - -interface AIRewriterCapabilities { - readonly available: AICapabilityAvailability; - - supportsTone(tone: AIRewriterTone): AICapabilityAvailability; - supportsFormat(format: AIRewriterFormat): AICapabilityAvailability; - supportsLength(length: AIRewriterLength): AICapabilityAvailability; - - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; -} - -// Translator -// https://github.com/WICG/translation-api?tab=readme-ov-file#full-api-surface-in-web-idl - -interface AITranslatorFactory { - create(options: AITranslatorCreateOptions): Promise; - capabilities(): Promise; -} - -interface AITranslator { - translate(input: string, options?: AITranslatorTranslateOptions): Promise; - translateStreaming(input: string, options?: AITranslatorTranslateOptions): ReadableStream; - - readonly sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier; - readonly targetLanguage: Intl.UnicodeBCP47LocaleIdentifier; - - destroy(): void; -} - -interface AITranslatorCapabilities { - readonly available: AICapabilityAvailability; - - languagePairAvailable( - sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier, - targetLanguage: Intl.UnicodeBCP47LocaleIdentifier, - ): AICapabilityAvailability; -} - -interface AITranslatorCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - sourceLanguage: Intl.UnicodeBCP47LocaleIdentifier; - targetLanguage: Intl.UnicodeBCP47LocaleIdentifier; -} - -interface AITranslatorTranslateOptions { - signal?: AbortSignal; -} - -// Language detector -// https://github.com/WICG/translation-api?tab=readme-ov-file#full-api-surface-in-web-idl - -interface AILanguageDetectorFactory { - create(options?: AILanguageDetectorCreateOptions): Promise; - capabilities(): Promise; -} - -interface AILanguageDetector { - detect(input: string, options?: AILanguageDetectorDetectOptions): Promise; - - destroy(): void; -} - -interface AILanguageDetectorCapabilities { - readonly available: AICapabilityAvailability; - - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; -} - -interface AILanguageDetectorCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; -} - -interface AILanguageDetectorDetectOptions { - signal?: AbortSignal; -} - -interface LanguageDetectionResult { - /** null represents unknown language */ - detectedLanguage: Intl.UnicodeBCP47LocaleIdentifier | null; - confidence: number; -} \ No newline at end of file From f100306fd5a37e65d02966b27f468c4644539aaf Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 25 Mar 2025 09:09:10 -0700 Subject: [PATCH 05/28] Assert HybridParams sets the model name --- packages/vertexai/src/api.test.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 4a0b978d858..bf97facb198 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -14,7 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ImagenModelParams, ModelParams, VertexAIErrorCode } from './types'; +import { + ImagenModelParams, + InferenceMode, + ModelParams, + VertexAIErrorCode +} from './types'; import { VertexAIError } from './errors'; import { ImagenModel, getGenerativeModel, getImagenModel } from './api'; import { expect } from 'chai'; @@ -101,6 +106,13 @@ describe('Top level API', () => { expect(genModel).to.be.an.instanceOf(GenerativeModel); expect(genModel.model).to.equal('publishers/google/models/my-model'); }); + it('getGenerativeModel with HybridParams sets the model', () => { + const genModel = getGenerativeModel(fakeVertexAI, { + mode: InferenceMode.ONLY_ON_CLOUD, + onCloudParams: { model: 'my-model' } + }); + expect(genModel.model).to.equal('publishers/google/models/my-model'); + }); it('getImagenModel throws if no model is provided', () => { try { getImagenModel(fakeVertexAI, {} as ImagenModelParams); From 15c4e450f4af6aff54bda5d4610dc1d3b218b478 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Wed, 26 Mar 2025 16:56:42 -0700 Subject: [PATCH 06/28] Use dom-chromium-ai package directly --- packages/vertexai/package.json | 1 + packages/vertexai/src/types/ai.ts | 65 ------------------- packages/vertexai/src/types/requests.ts | 1 - .../changelog-generator/tsconfig.json | 3 +- yarn.lock | 13 ++-- 5 files changed, 11 insertions(+), 72 deletions(-) delete mode 100644 packages/vertexai/src/types/ai.ts diff --git a/packages/vertexai/package.json b/packages/vertexai/package.json index 9faf562a535..076b6a1bc4a 100644 --- a/packages/vertexai/package.json +++ b/packages/vertexai/package.json @@ -58,6 +58,7 @@ "devDependencies": { "@firebase/app": "0.11.4", "@rollup/plugin-json": "6.1.0", + "@types/dom-chromium-ai": "0.0.6", "rollup": "2.79.2", "rollup-plugin-replace": "2.2.0", "rollup-plugin-typescript2": "0.36.0", diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts deleted file mode 100644 index 10cce1cab9b..00000000000 --- a/packages/vertexai/src/types/ai.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Shims @types/dom-chromium-ai - * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. - */ -interface AICreateMonitor extends EventTarget { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ondownloadprogress: ((this: AICreateMonitor, ev: DownloadProgressEvent) => any) | null; - - addEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, - options?: boolean | AddEventListenerOptions, - ): void; - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | AddEventListenerOptions, - ): void; - removeEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; -} - -interface DownloadProgressEvent extends Event { - readonly loaded: number; - readonly total: number; -} - -interface AICreateMonitorEventMap { - downloadprogress: DownloadProgressEvent; -} - -type AICreateMonitorCallback = (monitor: AICreateMonitor) => void; - -// Language Model -// https://github.com/explainers-by-googlers/prompt-api/#full-api-surface-in-web-idl - -interface AILanguageModelCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - topK?: number; - temperature?: number; -} - -export interface AILanguageModelCreateOptionsWithSystemPrompt extends AILanguageModelCreateOptions { - systemPrompt?: string; - initialPrompts?: AILanguageModelPrompt[]; -} - -type AILanguageModelPromptRole = "user" | "assistant"; - -interface AILanguageModelPrompt { - role: AILanguageModelPromptRole; - content: string; -} diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 9b01c7efd65..29164c2bd2b 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -16,7 +16,6 @@ */ import { TypedSchema } from '../requests/schema-builder'; -import { AILanguageModelCreateOptionsWithSystemPrompt } from './ai'; import { Content, Part } from './content'; import { FunctionCallingMode, diff --git a/repo-scripts/changelog-generator/tsconfig.json b/repo-scripts/changelog-generator/tsconfig.json index 38bdb7035e4..cffe622284d 100644 --- a/repo-scripts/changelog-generator/tsconfig.json +++ b/repo-scripts/changelog-generator/tsconfig.json @@ -3,7 +3,8 @@ "strict": true, "outDir": "dist", "lib": [ - "ESNext" + "ESNext", + "dom" ], "module": "CommonJS", "moduleResolution": "node", diff --git a/yarn.lock b/yarn.lock index 51ede769d03..fbfb49f23e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2938,17 +2938,20 @@ "@types/node" "*" "@types/cors@^2.8.12": - version "2.8.17" - resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" - integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== - dependencies: - "@types/node" "*" + version "2.8.12" + resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== "@types/deep-eql@*": version "4.0.2" resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== +"@types/dom-chromium-ai@0.0.6": + version "0.0.6" + resolved "https://registry.npmjs.org/@types/dom-chromium-ai/-/dom-chromium-ai-0.0.6.tgz#0c9e5712d8db3d26586cd9f175001b509cd2e514" + integrity sha512-/jUGe9a3BLzsjjg18Olk/Ul64PZ0P4aw8uNxrXeXVTni5PSxyCfyhHb4UohsXNVByOnwYGzlqUcb3vYKVsG4mg== + "@types/eslint-scope@^3.7.7": version "3.7.7" resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" From 97867186b3dde5c14afa7362302386f05d318598 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Wed, 26 Mar 2025 16:59:32 -0700 Subject: [PATCH 07/28] Use multi-line JSDoc comments for enum --- common/api-review/vertexai.api.md | 4 ---- packages/vertexai/src/types/enums.ts | 14 +++++++++++--- packages/vertexai/src/types/requests.ts | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 46d247853a5..49a690cee02 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -504,17 +504,13 @@ export interface ImagenSafetySettings { export interface HybridParams { mode?: InferenceMode; onCloudParams?: ModelParams; - // Warning: (ae-forgotten-export) The symbol "AILanguageModelCreateOptionsWithSystemPrompt" needs to be exported by the entry point index.d.ts onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; } // @public export enum InferenceMode { - // (undocumented) ONLY_ON_CLOUD = "ONLY_ON_CLOUD", - // (undocumented) ONLY_ON_DEVICE = "ONLY_ON_DEVICE", - // (undocumented) PREFER_ON_DEVICE = "PREFER_ON_DEVICE" } diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index f9eddc564f8..0955aebc9cf 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -246,10 +246,18 @@ export enum Modality { * @public */ export enum InferenceMode { - // Specifies the SDK should use on-device if possible, or fall back to on-cloud. + /** + * Uses the on-device model if available, or falls back to the on-cloud model. + */ PREFER_ON_DEVICE = 'PREFER_ON_DEVICE', - // Specifies the SDK must use on-device or throw. + + /** + * Exclusively uses the on-device model. Throws if one is not available. + */ ONLY_ON_DEVICE = 'ONLY_ON_DEVICE', - // Specifies the SDK must use on-cloud. + + /** + * Exclusively uses the on-cloud model. + */ ONLY_ON_CLOUD = 'ONLY_ON_CLOUD' } diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 29164c2bd2b..d589b49bb43 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -225,7 +225,7 @@ export interface HybridParams { */ mode?: InferenceMode; /** - * Optional. Specifies advanced params for on-device inference + * Optional. Specifies advanced params for on-device inference. */ onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; /** From c12b529f38d780251287ab9413c644c9a8e63e3d Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 27 Mar 2025 10:33:08 -0700 Subject: [PATCH 08/28] Use the existing name of the model params input --- packages/vertexai/src/api.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 323cfd10e80..7f11dd80844 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -71,18 +71,18 @@ export function getVertexAI( */ export function getGenerativeModel( vertexAI: VertexAI, - onCloudOrHybridParams: ModelParams | HybridParams, + modelParams: ModelParams | HybridParams, requestOptions?: RequestOptions ): GenerativeModel { - // Disambiguates onCloudOrHybridParams input. - const hybridParams = onCloudOrHybridParams as HybridParams; + // Uses the existence of HybridParams.mode to clarify the type of the modelParams input. + const hybridParams = modelParams as HybridParams; let onCloudParams: ModelParams; if (hybridParams.mode) { onCloudParams = hybridParams.onCloudParams || { model: 'gemini-2.0-flash-lite' }; } else { - onCloudParams = onCloudOrHybridParams as ModelParams; + onCloudParams = modelParams as ModelParams; } if (!onCloudParams.model) { From bbc83d9fd704c78604dd204d1f25d5a9bf76519e Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 27 Mar 2025 14:23:38 -0700 Subject: [PATCH 09/28] Run docgen:all --- common/api-review/vertexai.api.md | 16 +++---- docs-devsite/_toc.yaml | 2 + docs-devsite/vertexai.hybridparams.md | 57 +++++++++++++++++++++++++ docs-devsite/vertexai.md | 36 ++++++++++++---- docs-devsite/vertexai.modelparams.md | 2 +- docs-devsite/vertexai.requestoptions.md | 2 +- 6 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 docs-devsite/vertexai.hybridparams.md diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 49a690cee02..0af6e07f19e 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -344,7 +344,7 @@ export class GenerativeModel extends VertexAIModel { } // @public -export function getGenerativeModel(vertexAI: VertexAI, onCloudOrHybridParams: ModelParams | HybridParams, requestOptions?: RequestOptions): GenerativeModel; +export function getGenerativeModel(vertexAI: VertexAI, modelParams: ModelParams | HybridParams, requestOptions?: RequestOptions): GenerativeModel; // @beta export function getImagenModel(vertexAI: VertexAI, modelParams: ImagenModelParams, requestOptions?: RequestOptions): ImagenModel; @@ -416,6 +416,13 @@ export enum HarmSeverity { HARM_SEVERITY_NEGLIGIBLE = "HARM_SEVERITY_NEGLIGIBLE" } +// @public +export interface HybridParams { + mode?: InferenceMode; + onCloudParams?: ModelParams; + onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; +} + // @beta export enum ImagenAspectRatio { LANDSCAPE_16x9 = "16:9", @@ -500,13 +507,6 @@ export interface ImagenSafetySettings { safetyFilterLevel?: ImagenSafetyFilterLevel; } -// @public -export interface HybridParams { - mode?: InferenceMode; - onCloudParams?: ModelParams; - onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; -} - // @public export enum InferenceMode { ONLY_ON_CLOUD = "ONLY_ON_CLOUD", diff --git a/docs-devsite/_toc.yaml b/docs-devsite/_toc.yaml index 665222edb9d..64e24534590 100644 --- a/docs-devsite/_toc.yaml +++ b/docs-devsite/_toc.yaml @@ -536,6 +536,8 @@ toc: path: /docs/reference/js/vertexai.groundingattribution.md - title: GroundingMetadata path: /docs/reference/js/vertexai.groundingmetadata.md + - title: HybridParams + path: /docs/reference/js/vertexai.hybridparams.md - title: ImagenGCSImage path: /docs/reference/js/vertexai.imagengcsimage.md - title: ImagenGenerationConfig diff --git a/docs-devsite/vertexai.hybridparams.md b/docs-devsite/vertexai.hybridparams.md new file mode 100644 index 00000000000..9f340babccf --- /dev/null +++ b/docs-devsite/vertexai.hybridparams.md @@ -0,0 +1,57 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# HybridParams interface +Configures on-device and on-cloud inference. + +Signature: + +```typescript +export interface HybridParams +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. | +| [onCloudParams](./vertexai.hybridparams.md#hybridparamsoncloudparams) | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Optional. Specifies advanced params for on-cloud inference. | +| [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | AILanguageModelCreateOptionsWithSystemPrompt | Optional. Specifies advanced params for on-device inference. | + +## HybridParams.mode + +Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. + +Signature: + +```typescript +mode?: InferenceMode; +``` + +## HybridParams.onCloudParams + +Optional. Specifies advanced params for on-cloud inference. + +Signature: + +```typescript +onCloudParams?: ModelParams; +``` + +## HybridParams.onDeviceParams + +Optional. Specifies advanced params for on-device inference. + +Signature: + +```typescript +onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; +``` diff --git a/docs-devsite/vertexai.md b/docs-devsite/vertexai.md index f67254eef20..363905a9b49 100644 --- a/docs-devsite/vertexai.md +++ b/docs-devsite/vertexai.md @@ -19,8 +19,8 @@ The Vertex AI in Firebase Web SDK. | function(app, ...) | | [getVertexAI(app, options)](./vertexai.md#getvertexai_04094cf) | Returns a [VertexAI](./vertexai.vertexai.md#vertexai_interface) instance for the given app. | | function(vertexAI, ...) | -| [getGenerativeModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getgenerativemodel_e3037c9) | Returns a [GenerativeModel](./vertexai.generativemodel.md#generativemodel_class) class with methods for inference and other functionality. | -| [getImagenModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getimagenmodel_812c375) | (Public Preview) Returns an [ImagenModel](./vertexai.imagenmodel.md#imagenmodel_class) class with methods for using Imagen.Only Imagen 3 models (named imagen-3.0-*) are supported. | +| [getGenerativeModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getgenerativemodel_8dbc150) | Returns a [GenerativeModel](./vertexai.generativemodel.md#generativemodel_class) class with methods for inference and other functionality. | +| [getImagenModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getimagenmodel_812c375) | (Public Preview) Returns an [ImagenModel](./vertexai.imagenmodel.md#imagenmodel_class) class with methods for using Imagen.Only Imagen 3 models (named imagen-3.0-*) are supported. | ## Classes @@ -55,6 +55,7 @@ The Vertex AI in Firebase Web SDK. | [ImagenAspectRatio](./vertexai.md#imagenaspectratio) | (Public Preview) Aspect ratios for Imagen images.To specify an aspect ratio for generated images, set the aspectRatio property in your [ImagenGenerationConfig](./vertexai.imagengenerationconfig.md#imagengenerationconfig_interface).See the the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) for more details and examples of the supported aspect ratios. | | [ImagenPersonFilterLevel](./vertexai.md#imagenpersonfilterlevel) | (Public Preview) A filter level controlling whether generation of images containing people or faces is allowed.See the personGeneration documentation for more details. | | [ImagenSafetyFilterLevel](./vertexai.md#imagensafetyfilterlevel) | (Public Preview) A filter level controlling how aggressively to filter sensitive content.Text prompts provided as inputs and images (generated or uploaded) through Imagen on Vertex AI are assessed against a list of safety filters, which include 'harmful categories' (for example, violence, sexual, derogatory, and toxic). This filter level controls how aggressively to filter out potentially harmful content from responses. See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) and the [Responsible AI and usage guidelines](https://cloud.google.com/vertex-ai/generative-ai/docs/image/responsible-ai-imagen#safety-filters) for more details. | +| [InferenceMode](./vertexai.md#inferencemode) | Determines whether inference happens on-device or on-cloud. | | [Modality](./vertexai.md#modality) | Content part modality. | | [SchemaType](./vertexai.md#schematype) | Contains the list of OpenAPI data types as defined by the [OpenAPI specification](https://swagger.io/docs/specification/data-models/data-types/) | | [VertexAIErrorCode](./vertexai.md#vertexaierrorcode) | Standardized error codes that [VertexAIError](./vertexai.vertexaierror.md#vertexaierror_class) can have. | @@ -91,6 +92,7 @@ The Vertex AI in Firebase Web SDK. | [GenerativeContentBlob](./vertexai.generativecontentblob.md#generativecontentblob_interface) | Interface for sending an image. | | [GroundingAttribution](./vertexai.groundingattribution.md#groundingattribution_interface) | | | [GroundingMetadata](./vertexai.groundingmetadata.md#groundingmetadata_interface) | Metadata returned to client when grounding is enabled. | +| [HybridParams](./vertexai.hybridparams.md#hybridparams_interface) | Configures on-device and on-cloud inference. | | [ImagenGCSImage](./vertexai.imagengcsimage.md#imagengcsimage_interface) | An image generated by Imagen, stored in a Cloud Storage for Firebase bucket.This feature is not available yet. | | [ImagenGenerationConfig](./vertexai.imagengenerationconfig.md#imagengenerationconfig_interface) | (Public Preview) Configuration options for generating images with Imagen.See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images-imagen) for more details. | | [ImagenGenerationResponse](./vertexai.imagengenerationresponse.md#imagengenerationresponse_interface) | (Public Preview) The response from a request to generate images with Imagen. | @@ -99,10 +101,10 @@ The Vertex AI in Firebase Web SDK. | [ImagenSafetySettings](./vertexai.imagensafetysettings.md#imagensafetysettings_interface) | (Public Preview) Settings for controlling the aggressiveness of filtering out sensitive content.See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) for more details. | | [InlineDataPart](./vertexai.inlinedatapart.md#inlinedatapart_interface) | Content part interface if the part represents an image. | | [ModalityTokenCount](./vertexai.modalitytokencount.md#modalitytokencount_interface) | Represents token counting info for a single modality. | -| [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_e3037c9). | -| [ObjectSchemaInterface](./vertexai.objectschemainterface.md#objectschemainterface_interface) | Interface for [ObjectSchema](./vertexai.objectschema.md#objectschema_class) class. | +| [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | +| [ObjectSchemaInterface](./vertexai.objectschemainterface.md#objectschemainterface_interface) | Interface for [ObjectSchema](./vertexai.objectschema.md#objectschema_class) class. | | [PromptFeedback](./vertexai.promptfeedback.md#promptfeedback_interface) | If the prompt was blocked, this will be populated with blockReason and the relevant safetyRatings. | -| [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_e3037c9). | +| [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | | [RetrievedContextAttribution](./vertexai.retrievedcontextattribution.md#retrievedcontextattribution_interface) | | | [SafetyRating](./vertexai.safetyrating.md#safetyrating_interface) | A safety rating associated with a [GenerateContentCandidate](./vertexai.generatecontentcandidate.md#generatecontentcandidate_interface) | | [SafetySetting](./vertexai.safetysetting.md#safetysetting_interface) | Safety setting that can be sent as part of request parameters. | @@ -160,14 +162,14 @@ export declare function getVertexAI(app?: FirebaseApp, options?: VertexAIOptions ## function(vertexAI, ...) -### getGenerativeModel(vertexAI, modelParams, requestOptions) {:#getgenerativemodel_e3037c9} +### getGenerativeModel(vertexAI, modelParams, requestOptions) {:#getgenerativemodel_8dbc150} Returns a [GenerativeModel](./vertexai.generativemodel.md#generativemodel_class) class with methods for inference and other functionality. Signature: ```typescript -export declare function getGenerativeModel(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: RequestOptions): GenerativeModel; +export declare function getGenerativeModel(vertexAI: VertexAI, modelParams: ModelParams | HybridParams, requestOptions?: RequestOptions): GenerativeModel; ``` #### Parameters @@ -175,7 +177,7 @@ export declare function getGenerativeModel(vertexAI: VertexAI, modelParams: Mode | Parameter | Type | Description | | --- | --- | --- | | vertexAI | [VertexAI](./vertexai.vertexai.md#vertexai_interface) | | -| modelParams | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | | +| modelParams | [ModelParams](./vertexai.modelparams.md#modelparams_interface) \| [HybridParams](./vertexai.hybridparams.md#hybridparams_interface) | | | requestOptions | [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | | Returns: @@ -489,6 +491,24 @@ export declare enum ImagenSafetyFilterLevel | BLOCK\_NONE | "block_none" | (Public Preview) The least aggressive filtering level; blocks very few sensitive prompts and responses.Access to this feature is restricted and may require your case to be reviewed and approved by Cloud support. | | BLOCK\_ONLY\_HIGH | "block_only_high" | (Public Preview) Blocks few sensitive prompts and responses. | +## InferenceMode + +Determines whether inference happens on-device or on-cloud. + +Signature: + +```typescript +export declare enum InferenceMode +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| ONLY\_ON\_CLOUD | "ONLY_ON_CLOUD" | Exclusively uses the on-cloud model. | +| ONLY\_ON\_DEVICE | "ONLY_ON_DEVICE" | Exclusively uses the on-device model. Throws if one is not available. | +| PREFER\_ON\_DEVICE | "PREFER_ON_DEVICE" | Uses the on-device model if available, or falls back to the on-cloud model. | + ## Modality Content part modality. diff --git a/docs-devsite/vertexai.modelparams.md b/docs-devsite/vertexai.modelparams.md index d3963d240eb..fe7b7d37c30 100644 --- a/docs-devsite/vertexai.modelparams.md +++ b/docs-devsite/vertexai.modelparams.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # ModelParams interface -Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_e3037c9). +Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). Signature: diff --git a/docs-devsite/vertexai.requestoptions.md b/docs-devsite/vertexai.requestoptions.md index dcd0c552ecb..9e174c12a32 100644 --- a/docs-devsite/vertexai.requestoptions.md +++ b/docs-devsite/vertexai.requestoptions.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # RequestOptions interface -Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_e3037c9). +Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). Signature: From 33db72a72e4fdb22b99f01d0174ecce0c55a97bb Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 27 Mar 2025 16:41:07 -0700 Subject: [PATCH 10/28] Use in-cloud phrasing --- packages/vertexai/src/api.test.ts | 4 ++-- packages/vertexai/src/api.ts | 10 +++++----- packages/vertexai/src/types/enums.ts | 8 ++++---- packages/vertexai/src/types/requests.ts | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index bf97facb198..030fb086d95 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -108,8 +108,8 @@ describe('Top level API', () => { }); it('getGenerativeModel with HybridParams sets the model', () => { const genModel = getGenerativeModel(fakeVertexAI, { - mode: InferenceMode.ONLY_ON_CLOUD, - onCloudParams: { model: 'my-model' } + mode: InferenceMode.ONLY_IN_CLOUD, + inCloudParams: { model: 'my-model' } }); expect(genModel.model).to.equal('publishers/google/models/my-model'); }); diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 7f11dd80844..c481fefa44b 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -76,22 +76,22 @@ export function getGenerativeModel( ): GenerativeModel { // Uses the existence of HybridParams.mode to clarify the type of the modelParams input. const hybridParams = modelParams as HybridParams; - let onCloudParams: ModelParams; + let inCloudParams: ModelParams; if (hybridParams.mode) { - onCloudParams = hybridParams.onCloudParams || { + inCloudParams = hybridParams.inCloudParams || { model: 'gemini-2.0-flash-lite' }; } else { - onCloudParams = modelParams as ModelParams; + inCloudParams = modelParams as ModelParams; } - if (!onCloudParams.model) { + if (!inCloudParams.model) { throw new VertexAIError( VertexAIErrorCode.NO_MODEL, `Must provide a model name. Example: getGenerativeModel({ model: 'my-model-name' })` ); } - return new GenerativeModel(vertexAI, onCloudParams, requestOptions); + return new GenerativeModel(vertexAI, inCloudParams, requestOptions); } /** diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index 0955aebc9cf..953078033b3 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -242,12 +242,12 @@ export enum Modality { } /** - * Determines whether inference happens on-device or on-cloud. + * Determines whether inference happens on-device or in-cloud. * @public */ export enum InferenceMode { /** - * Uses the on-device model if available, or falls back to the on-cloud model. + * Uses the on-device model if available, or falls back to the in-cloud model. */ PREFER_ON_DEVICE = 'PREFER_ON_DEVICE', @@ -257,7 +257,7 @@ export enum InferenceMode { ONLY_ON_DEVICE = 'ONLY_ON_DEVICE', /** - * Exclusively uses the on-cloud model. + * Exclusively uses the in-cloud model. */ - ONLY_ON_CLOUD = 'ONLY_ON_CLOUD' + ONLY_IN_CLOUD = 'ONLY_IN_CLOUD' } diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index d589b49bb43..8d1fe68519c 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -216,12 +216,12 @@ export interface FunctionCallingConfig { } /** - * Configures on-device and on-cloud inference. + * Configures on-device and in-cloud inference. * @public */ export interface HybridParams { /** - * Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. + * Optional. Specifies on-device or in-cloud inference. Defaults to prefer on-device. */ mode?: InferenceMode; /** @@ -229,7 +229,7 @@ export interface HybridParams { */ onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; /** - * Optional. Specifies advanced params for on-cloud inference. + * Optional. Specifies advanced params for in-cloud inference. */ - onCloudParams?: ModelParams; + inCloudParams?: ModelParams; } From 4f22b15211cfb5d4c89e0a6d255e60394dc0cbdb Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Fri, 28 Mar 2025 16:41:54 -0700 Subject: [PATCH 11/28] Parameterize default in-cloud model name --- common/api-review/vertexai.api.md | 7 ++++--- packages/vertexai/src/api.test.ts | 10 +++++++++- packages/vertexai/src/api.ts | 2 +- packages/vertexai/src/models/generative-model.ts | 4 ++++ packages/vertexai/src/types/enums.ts | 1 - packages/vertexai/src/types/requests.ts | 7 +++---- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 0af6e07f19e..d452077f313 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -326,6 +326,7 @@ export interface GenerativeContentBlob { export class GenerativeModel extends VertexAIModel { constructor(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: RequestOptions); countTokens(request: CountTokensRequest | string | Array): Promise; + static DEFAULT_HYBRID_IN_CLOUD_MODEL: string; generateContent(request: GenerateContentRequest | string | Array): Promise; generateContentStream(request: GenerateContentRequest | string | Array): Promise; // (undocumented) @@ -418,8 +419,8 @@ export enum HarmSeverity { // @public export interface HybridParams { - mode?: InferenceMode; - onCloudParams?: ModelParams; + inCloudParams?: ModelParams; + mode: InferenceMode; onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; } @@ -509,7 +510,7 @@ export interface ImagenSafetySettings { // @public export enum InferenceMode { - ONLY_ON_CLOUD = "ONLY_ON_CLOUD", + ONLY_IN_CLOUD = "ONLY_IN_CLOUD", ONLY_ON_DEVICE = "ONLY_ON_DEVICE", PREFER_ON_DEVICE = "PREFER_ON_DEVICE" } diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 030fb086d95..aeb090e24c5 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -106,7 +106,15 @@ describe('Top level API', () => { expect(genModel).to.be.an.instanceOf(GenerativeModel); expect(genModel.model).to.equal('publishers/google/models/my-model'); }); - it('getGenerativeModel with HybridParams sets the model', () => { + it('getGenerativeModel with HybridParams sets a default model', () => { + const genModel = getGenerativeModel(fakeVertexAI, { + mode: InferenceMode.ONLY_ON_DEVICE + }); + expect(genModel.model).to.equal( + `publishers/google/models/${GenerativeModel.DEFAULT_HYBRID_IN_CLOUD_MODEL}` + ); + }); + it('getGenerativeModel with HybridParams honors a model override', () => { const genModel = getGenerativeModel(fakeVertexAI, { mode: InferenceMode.ONLY_IN_CLOUD, inCloudParams: { model: 'my-model' } diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index c481fefa44b..2b8536dd89f 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -79,7 +79,7 @@ export function getGenerativeModel( let inCloudParams: ModelParams; if (hybridParams.mode) { inCloudParams = hybridParams.inCloudParams || { - model: 'gemini-2.0-flash-lite' + model: GenerativeModel.DEFAULT_HYBRID_IN_CLOUD_MODEL }; } else { inCloudParams = modelParams as ModelParams; diff --git a/packages/vertexai/src/models/generative-model.ts b/packages/vertexai/src/models/generative-model.ts index 983118bf6ff..32406ea19f7 100644 --- a/packages/vertexai/src/models/generative-model.ts +++ b/packages/vertexai/src/models/generative-model.ts @@ -49,6 +49,10 @@ import { VertexAIModel } from './vertexai-model'; * @public */ export class GenerativeModel extends VertexAIModel { + /** + * Defines the name of the default in-cloud model to use for hybrid inference. + */ + static DEFAULT_HYBRID_IN_CLOUD_MODEL = 'gemini-2.0-flash-lite'; generationConfig: GenerationConfig; safetySettings: SafetySetting[]; requestOptions?: RequestOptions; diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index 953078033b3..57629e5c9f5 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -243,7 +243,6 @@ export enum Modality { /** * Determines whether inference happens on-device or in-cloud. - * @public */ export enum InferenceMode { /** diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 8d1fe68519c..0d7d22f3b04 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -216,14 +216,13 @@ export interface FunctionCallingConfig { } /** - * Configures on-device and in-cloud inference. - * @public + * Toggles hybrid inference. */ export interface HybridParams { /** - * Optional. Specifies on-device or in-cloud inference. Defaults to prefer on-device. + * Specifies on-device or in-cloud inference. Defaults to prefer on-device. */ - mode?: InferenceMode; + mode: InferenceMode; /** * Optional. Specifies advanced params for on-device inference. */ From 6df85278bbbfb7b5f3efd26785497219cf717d83 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 1 Apr 2025 17:44:30 -0700 Subject: [PATCH 12/28] Use type for inference mode and update docs --- common/api-review/vertexai.api.md | 6 +---- docs-devsite/vertexai.generativemodel.md | 11 ++++++++ docs-devsite/vertexai.hybridparams.md | 18 ++++++------- docs-devsite/vertexai.md | 32 +++++++++--------------- packages/vertexai/src/api.test.ts | 5 ++-- packages/vertexai/src/types/enums.ts | 20 --------------- packages/vertexai/src/types/requests.ts | 10 ++++++-- 7 files changed, 43 insertions(+), 59 deletions(-) diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index d452077f313..ef7d0b4f300 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -509,11 +509,7 @@ export interface ImagenSafetySettings { } // @public -export enum InferenceMode { - ONLY_IN_CLOUD = "ONLY_IN_CLOUD", - ONLY_ON_DEVICE = "ONLY_ON_DEVICE", - PREFER_ON_DEVICE = "PREFER_ON_DEVICE" -} +export type InferenceMode = 'prefer_on_device' | 'only_on_device' | 'only_in_cloud'; // @public export interface InlineDataPart { diff --git a/docs-devsite/vertexai.generativemodel.md b/docs-devsite/vertexai.generativemodel.md index e4a238b0af5..831ec5d4369 100644 --- a/docs-devsite/vertexai.generativemodel.md +++ b/docs-devsite/vertexai.generativemodel.md @@ -29,6 +29,7 @@ export declare class GenerativeModel extends VertexAIModel | Property | Modifiers | Type | Description | | --- | --- | --- | --- | +| [DEFAULT\_HYBRID\_IN\_CLOUD\_MODEL](./vertexai.generativemodel.md#generativemodeldefault_hybrid_in_cloud_model) | static | string | Defines the name of the default in-cloud model to use for hybrid inference. | | [generationConfig](./vertexai.generativemodel.md#generativemodelgenerationconfig) | | [GenerationConfig](./vertexai.generationconfig.md#generationconfig_interface) | | | [requestOptions](./vertexai.generativemodel.md#generativemodelrequestoptions) | | [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | | | [safetySettings](./vertexai.generativemodel.md#generativemodelsafetysettings) | | [SafetySetting](./vertexai.safetysetting.md#safetysetting_interface)\[\] | | @@ -63,6 +64,16 @@ constructor(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: Reque | modelParams | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | | | requestOptions | [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | | +## GenerativeModel.DEFAULT\_HYBRID\_IN\_CLOUD\_MODEL + +Defines the name of the default in-cloud model to use for hybrid inference. + +Signature: + +```typescript +static DEFAULT_HYBRID_IN_CLOUD_MODEL: string; +``` + ## GenerativeModel.generationConfig Signature: diff --git a/docs-devsite/vertexai.hybridparams.md b/docs-devsite/vertexai.hybridparams.md index 9f340babccf..912f5e43c36 100644 --- a/docs-devsite/vertexai.hybridparams.md +++ b/docs-devsite/vertexai.hybridparams.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # HybridParams interface -Configures on-device and on-cloud inference. +Toggles hybrid inference. Signature: @@ -22,28 +22,28 @@ export interface HybridParams | Property | Type | Description | | --- | --- | --- | -| [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. | -| [onCloudParams](./vertexai.hybridparams.md#hybridparamsoncloudparams) | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Optional. Specifies advanced params for on-cloud inference. | +| [inCloudParams](./vertexai.hybridparams.md#hybridparamsincloudparams) | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Optional. Specifies advanced params for in-cloud inference. | +| [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Specifies on-device or in-cloud inference. Defaults to prefer on-device. | | [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | AILanguageModelCreateOptionsWithSystemPrompt | Optional. Specifies advanced params for on-device inference. | -## HybridParams.mode +## HybridParams.inCloudParams -Optional. Specifies on-device or on-cloud inference. Defaults to prefer on-device. +Optional. Specifies advanced params for in-cloud inference. Signature: ```typescript -mode?: InferenceMode; +inCloudParams?: ModelParams; ``` -## HybridParams.onCloudParams +## HybridParams.mode -Optional. Specifies advanced params for on-cloud inference. +Specifies on-device or in-cloud inference. Defaults to prefer on-device. Signature: ```typescript -onCloudParams?: ModelParams; +mode: InferenceMode; ``` ## HybridParams.onDeviceParams diff --git a/docs-devsite/vertexai.md b/docs-devsite/vertexai.md index 363905a9b49..44ae7294735 100644 --- a/docs-devsite/vertexai.md +++ b/docs-devsite/vertexai.md @@ -55,7 +55,6 @@ The Vertex AI in Firebase Web SDK. | [ImagenAspectRatio](./vertexai.md#imagenaspectratio) | (Public Preview) Aspect ratios for Imagen images.To specify an aspect ratio for generated images, set the aspectRatio property in your [ImagenGenerationConfig](./vertexai.imagengenerationconfig.md#imagengenerationconfig_interface).See the the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) for more details and examples of the supported aspect ratios. | | [ImagenPersonFilterLevel](./vertexai.md#imagenpersonfilterlevel) | (Public Preview) A filter level controlling whether generation of images containing people or faces is allowed.See the personGeneration documentation for more details. | | [ImagenSafetyFilterLevel](./vertexai.md#imagensafetyfilterlevel) | (Public Preview) A filter level controlling how aggressively to filter sensitive content.Text prompts provided as inputs and images (generated or uploaded) through Imagen on Vertex AI are assessed against a list of safety filters, which include 'harmful categories' (for example, violence, sexual, derogatory, and toxic). This filter level controls how aggressively to filter out potentially harmful content from responses. See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) and the [Responsible AI and usage guidelines](https://cloud.google.com/vertex-ai/generative-ai/docs/image/responsible-ai-imagen#safety-filters) for more details. | -| [InferenceMode](./vertexai.md#inferencemode) | Determines whether inference happens on-device or on-cloud. | | [Modality](./vertexai.md#modality) | Content part modality. | | [SchemaType](./vertexai.md#schematype) | Contains the list of OpenAPI data types as defined by the [OpenAPI specification](https://swagger.io/docs/specification/data-models/data-types/) | | [VertexAIErrorCode](./vertexai.md#vertexaierrorcode) | Standardized error codes that [VertexAIError](./vertexai.vertexaierror.md#vertexaierror_class) can have. | @@ -92,7 +91,7 @@ The Vertex AI in Firebase Web SDK. | [GenerativeContentBlob](./vertexai.generativecontentblob.md#generativecontentblob_interface) | Interface for sending an image. | | [GroundingAttribution](./vertexai.groundingattribution.md#groundingattribution_interface) | | | [GroundingMetadata](./vertexai.groundingmetadata.md#groundingmetadata_interface) | Metadata returned to client when grounding is enabled. | -| [HybridParams](./vertexai.hybridparams.md#hybridparams_interface) | Configures on-device and on-cloud inference. | +| [HybridParams](./vertexai.hybridparams.md#hybridparams_interface) | Toggles hybrid inference. | | [ImagenGCSImage](./vertexai.imagengcsimage.md#imagengcsimage_interface) | An image generated by Imagen, stored in a Cloud Storage for Firebase bucket.This feature is not available yet. | | [ImagenGenerationConfig](./vertexai.imagengenerationconfig.md#imagengenerationconfig_interface) | (Public Preview) Configuration options for generating images with Imagen.See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images-imagen) for more details. | | [ImagenGenerationResponse](./vertexai.imagengenerationresponse.md#imagengenerationresponse_interface) | (Public Preview) The response from a request to generate images with Imagen. | @@ -132,6 +131,7 @@ The Vertex AI in Firebase Web SDK. | Type Alias | Description | | --- | --- | +| [InferenceMode](./vertexai.md#inferencemode) | Determines whether inference happens on-device or in-cloud. | | [Part](./vertexai.md#part) | Content part - includes text, image/video, or function call/response part types. | | [Role](./vertexai.md#role) | Role is the producer of the content. | | [Tool](./vertexai.md#tool) | Defines a tool that model can call to access external knowledge. | @@ -225,6 +225,16 @@ Possible roles. POSSIBLE_ROLES: readonly ["user", "model", "function", "system"] ``` +## InferenceMode + +Determines whether inference happens on-device or in-cloud. + +Signature: + +```typescript +export type InferenceMode = 'prefer_on_device' | 'only_on_device' | 'only_in_cloud'; +``` + ## Part Content part - includes text, image/video, or function call/response part types. @@ -491,24 +501,6 @@ export declare enum ImagenSafetyFilterLevel | BLOCK\_NONE | "block_none" | (Public Preview) The least aggressive filtering level; blocks very few sensitive prompts and responses.Access to this feature is restricted and may require your case to be reviewed and approved by Cloud support. | | BLOCK\_ONLY\_HIGH | "block_only_high" | (Public Preview) Blocks few sensitive prompts and responses. | -## InferenceMode - -Determines whether inference happens on-device or on-cloud. - -Signature: - -```typescript -export declare enum InferenceMode -``` - -## Enumeration Members - -| Member | Value | Description | -| --- | --- | --- | -| ONLY\_ON\_CLOUD | "ONLY_ON_CLOUD" | Exclusively uses the on-cloud model. | -| ONLY\_ON\_DEVICE | "ONLY_ON_DEVICE" | Exclusively uses the on-device model. Throws if one is not available. | -| PREFER\_ON\_DEVICE | "PREFER_ON_DEVICE" | Uses the on-device model if available, or falls back to the on-cloud model. | - ## Modality Content part modality. diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index aeb090e24c5..0f25384071a 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -16,7 +16,6 @@ */ import { ImagenModelParams, - InferenceMode, ModelParams, VertexAIErrorCode } from './types'; @@ -108,7 +107,7 @@ describe('Top level API', () => { }); it('getGenerativeModel with HybridParams sets a default model', () => { const genModel = getGenerativeModel(fakeVertexAI, { - mode: InferenceMode.ONLY_ON_DEVICE + mode: 'only_on_device' }); expect(genModel.model).to.equal( `publishers/google/models/${GenerativeModel.DEFAULT_HYBRID_IN_CLOUD_MODEL}` @@ -116,7 +115,7 @@ describe('Top level API', () => { }); it('getGenerativeModel with HybridParams honors a model override', () => { const genModel = getGenerativeModel(fakeVertexAI, { - mode: InferenceMode.ONLY_IN_CLOUD, + mode: 'only_in_cloud', inCloudParams: { model: 'my-model' } }); expect(genModel.model).to.equal('publishers/google/models/my-model'); diff --git a/packages/vertexai/src/types/enums.ts b/packages/vertexai/src/types/enums.ts index 57629e5c9f5..a9481d40f5f 100644 --- a/packages/vertexai/src/types/enums.ts +++ b/packages/vertexai/src/types/enums.ts @@ -240,23 +240,3 @@ export enum Modality { */ DOCUMENT = 'DOCUMENT' } - -/** - * Determines whether inference happens on-device or in-cloud. - */ -export enum InferenceMode { - /** - * Uses the on-device model if available, or falls back to the in-cloud model. - */ - PREFER_ON_DEVICE = 'PREFER_ON_DEVICE', - - /** - * Exclusively uses the on-device model. Throws if one is not available. - */ - ONLY_ON_DEVICE = 'ONLY_ON_DEVICE', - - /** - * Exclusively uses the in-cloud model. - */ - ONLY_IN_CLOUD = 'ONLY_IN_CLOUD' -} diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 0d7d22f3b04..62d0c69a3ba 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -21,8 +21,7 @@ import { FunctionCallingMode, HarmBlockMethod, HarmBlockThreshold, - HarmCategory, - InferenceMode + HarmCategory } from './enums'; import { ObjectSchemaInterface, SchemaRequest } from './schema'; @@ -232,3 +231,10 @@ export interface HybridParams { */ inCloudParams?: ModelParams; } +/** + * Determines whether inference happens on-device or in-cloud. + */ +export type InferenceMode = + | 'prefer_on_device' + | 'only_on_device' + | 'only_in_cloud'; From 7a6c8e99c9162b64c758e61807b03c1c49621418 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 3 Apr 2025 13:58:15 -0700 Subject: [PATCH 13/28] Run yarn format --- packages/vertexai/src/api.test.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 0f25384071a..2852e9c3f1f 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -14,11 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - ImagenModelParams, - ModelParams, - VertexAIErrorCode -} from './types'; +import { ImagenModelParams, ModelParams, VertexAIErrorCode } from './types'; import { VertexAIError } from './errors'; import { ImagenModel, getGenerativeModel, getImagenModel } from './api'; import { expect } from 'chai'; From eac3d4caaa6d7de4440ee21820793bc090eb413e Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 14 Apr 2025 16:07:16 -0700 Subject: [PATCH 14/28] rebased and updated deps --- package.json | 15 +++++--- packages/vertexai/package.json | 1 + scripts/release/utils/workspace.ts | 6 ++-- yarn.lock | 58 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 30b6b09a003..91a1c9316de 100644 --- a/package.json +++ b/package.json @@ -56,11 +56,16 @@ "type": "git", "url": "git+https://github.com/firebase/firebase-js-sdk.git" }, - "workspaces": [ - "packages/*", - "integration/*", - "repo-scripts/*" - ], + "workspaces": { + "packages": [ + "packages/*", + "integration/*", + "repo-scripts/*" + ], + "nohoist": [ + "**/vertexai/@types/dom-chromium-ai" + ] + }, "devDependencies": { "@babel/core": "7.26.8", "@babel/plugin-transform-modules-commonjs": "7.26.3", diff --git a/packages/vertexai/package.json b/packages/vertexai/package.json index 076b6a1bc4a..d75ad262aac 100644 --- a/packages/vertexai/package.json +++ b/packages/vertexai/package.json @@ -52,6 +52,7 @@ "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", "@firebase/util": "1.11.0", + "@types/dom-chromium-ai": "0.0.6", "tslib": "^2.1.0" }, "license": "Apache-2.0", diff --git a/scripts/release/utils/workspace.ts b/scripts/release/utils/workspace.ts index 077e3124b2a..3dba8651675 100644 --- a/scripts/release/utils/workspace.ts +++ b/scripts/release/utils/workspace.ts @@ -27,8 +27,10 @@ const writeFile = promisify(_writeFile); const { workspaces: rawWorkspaces -}: { workspaces: string[] } = require(`${root}/package.json`); -const workspaces = rawWorkspaces.map(workspace => `${root}/${workspace}`); +}: { workspaces: { packages: string[] } } = require(`${root}/package.json`); +const workspaces = rawWorkspaces.packages.map( + workspace => `${root}/${workspace}` +); export function mapWorkspaceToPackages( workspaces: string[] diff --git a/yarn.lock b/yarn.lock index fbfb49f23e0..6c92b4aeb35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1299,6 +1299,28 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== +"@firebase/app@0.11.4": + version "0.11.4" + resolved "https://registry.npmjs.org/@firebase/app/-/app-0.11.4.tgz#93f2637ed5b8dbc1ddf879c727d66a00c656c959" + integrity sha512-GPREsZjfSaHzwyC6cI/Cqvzf6zxqMzya+25tSpUstdqC2w0IdfxEfOMjfdW7bDfVEf4Rb4Nb6gfoOAgVSp4c4g== + dependencies: + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/vertexai@1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.2.0.tgz#8f8a4ae75284c3067c0a06c7d0bef922571e6dd7" + integrity sha512-WUYIzFpOipjFXT2i0hT26wivJoIximizQptVs3KAxFAqbVlO8sjKPsMkgz0bh+tdKlqP4SUDda71fMUZXUKHgA== + dependencies: + "@firebase/app-check-interop-types" "0.3.3" + "@firebase/component" "0.6.13" + "@firebase/logger" "0.4.4" + "@firebase/util" "1.11.0" + tslib "^2.1.0" + "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -3166,6 +3188,13 @@ dependencies: undici-types "~5.26.4" +"@types/node@18.19.83": + version "18.19.83" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.83.tgz#44d302cd09364640bdd45d001bc75e596f7da920" + integrity sha512-D69JeR5SfFS5H6FLbUaS0vE4r1dGhmMBbG4Ed6BNS4wkDK8GZjsdCShT5LCN59vOHEUHnFCY9J4aclXlIphMkA== + dependencies: + undici-types "~5.26.4" + "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -16931,6 +16960,35 @@ webpack@^5: watchpack "^2.4.1" webpack-sources "^3.2.3" +webpack@5.98.0: + version "5.98.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz#44ae19a8f2ba97537978246072fb89d10d1fbd17" + integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA== + dependencies: + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" + "@webassemblyjs/ast" "^1.14.1" + "@webassemblyjs/wasm-edit" "^1.14.1" + "@webassemblyjs/wasm-parser" "^1.14.1" + acorn "^8.14.0" + browserslist "^4.24.0" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.17.1" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^4.3.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.11" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + websocket-driver@>=0.5.1: version "0.7.4" resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" From c6a17b0c9bdc82cd0a517353859b987a521d53f6 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 14 Apr 2025 16:11:47 -0700 Subject: [PATCH 15/28] revert deps --- package.json | 6 +-- packages/vertexai/package.json | 6 +-- yarn.lock | 87 ++++------------------------------ 3 files changed, 15 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index 91a1c9316de..43589733b54 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "@types/long": "4.0.2", "@types/mocha": "9.1.1", "@types/mz": "2.7.8", - "@types/node": "18.19.83", + "@types/node": "18.19.75", "@types/request": "2.48.12", "@types/sinon": "9.0.11", "@types/sinon-chai": "3.2.12", @@ -144,7 +144,7 @@ "nyc": "15.1.0", "ora": "5.4.1", "patch-package": "7.0.2", - "playwright": "1.51.1", + "playwright": "1.50.1", "postinstall-postinstall": "2.1.0", "prettier": "2.8.8", "protractor": "5.4.2", @@ -163,7 +163,7 @@ "typedoc": "0.16.11", "typescript": "5.5.4", "watch": "1.0.2", - "webpack": "5.98.0", + "webpack": "5.97.1", "yargs": "17.7.2" } } diff --git a/packages/vertexai/package.json b/packages/vertexai/package.json index d75ad262aac..c53cb5d3f48 100644 --- a/packages/vertexai/package.json +++ b/packages/vertexai/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/vertexai", - "version": "1.2.1", + "version": "1.2.0", "description": "A Firebase SDK for VertexAI", "author": "Firebase (https://firebase.google.com/)", "engines": { @@ -57,7 +57,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.11.4", + "@firebase/app": "0.11.3", "@rollup/plugin-json": "6.1.0", "@types/dom-chromium-ai": "0.0.6", "rollup": "2.79.2", @@ -80,4 +80,4 @@ ], "reportDir": "./coverage/node" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 6c92b4aeb35..adbe420e7b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1299,28 +1299,6 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@firebase/app@0.11.4": - version "0.11.4" - resolved "https://registry.npmjs.org/@firebase/app/-/app-0.11.4.tgz#93f2637ed5b8dbc1ddf879c727d66a00c656c959" - integrity sha512-GPREsZjfSaHzwyC6cI/Cqvzf6zxqMzya+25tSpUstdqC2w0IdfxEfOMjfdW7bDfVEf4Rb4Nb6gfoOAgVSp4c4g== - dependencies: - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - idb "7.1.1" - tslib "^2.1.0" - -"@firebase/vertexai@1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.2.0.tgz#8f8a4ae75284c3067c0a06c7d0bef922571e6dd7" - integrity sha512-WUYIzFpOipjFXT2i0hT26wivJoIximizQptVs3KAxFAqbVlO8sjKPsMkgz0bh+tdKlqP4SUDda71fMUZXUKHgA== - dependencies: - "@firebase/app-check-interop-types" "0.3.3" - "@firebase/component" "0.6.13" - "@firebase/logger" "0.4.4" - "@firebase/util" "1.11.0" - tslib "^2.1.0" - "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -3188,13 +3166,6 @@ dependencies: undici-types "~5.26.4" -"@types/node@18.19.83": - version "18.19.83" - resolved "https://registry.npmjs.org/@types/node/-/node-18.19.83.tgz#44d302cd09364640bdd45d001bc75e596f7da920" - integrity sha512-D69JeR5SfFS5H6FLbUaS0vE4r1dGhmMBbG4Ed6BNS4wkDK8GZjsdCShT5LCN59vOHEUHnFCY9J4aclXlIphMkA== - dependencies: - undici-types "~5.26.4" - "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -13244,17 +13215,17 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.51.1: - version "1.51.1" - resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz#d57f0393e02416f32a47cf82b27533656a8acce1" - integrity sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw== +playwright-core@1.50.1: + version "1.50.1" + resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz#6a0484f1f1c939168f40f0ab3828c4a1592c4504" + integrity sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ== -playwright@1.51.1: - version "1.51.1" - resolved "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz#ae1467ee318083968ad28d6990db59f47a55390f" - integrity sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw== +playwright@1.50.1: + version "1.50.1" + resolved "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz#2f93216511d65404f676395bfb97b41aa052b180" + integrity sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw== dependencies: - playwright-core "1.51.1" + playwright-core "1.50.1" optionalDependencies: fsevents "2.3.2" @@ -15772,17 +15743,6 @@ terser-webpack-plugin@^5.3.10: serialize-javascript "^6.0.2" terser "^5.31.1" -terser-webpack-plugin@^5.3.11: - version "5.3.14" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz#9031d48e57ab27567f02ace85c7d690db66c3e06" - integrity sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - jest-worker "^27.4.5" - schema-utils "^4.3.0" - serialize-javascript "^6.0.2" - terser "^5.31.1" - terser@5.37.0, terser@^5.17.4, terser@^5.31.1: version "5.37.0" resolved "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3" @@ -16960,35 +16920,6 @@ webpack@^5: watchpack "^2.4.1" webpack-sources "^3.2.3" -webpack@5.98.0: - version "5.98.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz#44ae19a8f2ba97537978246072fb89d10d1fbd17" - integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA== - dependencies: - "@types/eslint-scope" "^3.7.7" - "@types/estree" "^1.0.6" - "@webassemblyjs/ast" "^1.14.1" - "@webassemblyjs/wasm-edit" "^1.14.1" - "@webassemblyjs/wasm-parser" "^1.14.1" - acorn "^8.14.0" - browserslist "^4.24.0" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.1" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.11" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^4.3.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.11" - watchpack "^2.4.1" - webpack-sources "^3.2.3" - websocket-driver@>=0.5.1: version "0.7.4" resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" From 6ccdc0e15aa9671e8d5a487d33b306c87f9c9390 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 15 Apr 2025 10:45:48 -0700 Subject: [PATCH 16/28] Remove erroneous type dep --- packages/vertexai/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vertexai/package.json b/packages/vertexai/package.json index c53cb5d3f48..09f4d80b4d5 100644 --- a/packages/vertexai/package.json +++ b/packages/vertexai/package.json @@ -52,7 +52,6 @@ "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", "@firebase/util": "1.11.0", - "@types/dom-chromium-ai": "0.0.6", "tslib": "^2.1.0" }, "license": "Apache-2.0", From b07bdacdd5866ea3ae02f0a85a7ac6fcc6c6ae4b Mon Sep 17 00:00:00 2001 From: gsiddh <92327772+gsiddh@users.noreply.github.com> Date: Tue, 15 Apr 2025 15:35:13 -0700 Subject: [PATCH 17/28] Vaihi add langmodel types. (#8927) * Adding LanguageModel types. These are based off https://github.com/webmachinelearning/prompt-api?tab=readme-ov-file#full-api-surface-in-web-idl * Adding LanguageModel types. * Remove bunch of exports * yarn formatted * after lint --- packages/vertexai/src/types/language-model.ts | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 packages/vertexai/src/types/language-model.ts diff --git a/packages/vertexai/src/types/language-model.ts b/packages/vertexai/src/types/language-model.ts new file mode 100644 index 00000000000..5bfb38beea4 --- /dev/null +++ b/packages/vertexai/src/types/language-model.ts @@ -0,0 +1,83 @@ +/** + * @license + * Copyright 2025 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 interface LanguageModel extends EventTarget { + create(options?: LanguageModelCreateOptions): Promise; + availability(options?: LanguageModelCreateCoreOptions): Promise; + prompt( + input: LanguageModelPrompt, + options?: LanguageModelPromptOptions + ): Promise; + promptStreaming( + input: LanguageModelPrompt, + options?: LanguageModelPromptOptions + ): ReadableStream; + measureInputUsage( + input: LanguageModelPrompt, + options?: LanguageModelPromptOptions + ): Promise; + destroy(): undefined; +} +enum Availability { + 'unavailable', + 'downloadable', + 'downloading', + 'available' +} +interface LanguageModelCreateCoreOptions { + topK?: number; + temperature?: number; + expectedInputs?: LanguageModelExpectedInput[]; +} +interface LanguageModelCreateOptions extends LanguageModelCreateCoreOptions { + signal?: AbortSignal; + systemPrompt?: string; + initialPrompts?: LanguageModelInitialPrompts; +} +interface LanguageModelPromptOptions { + signal?: AbortSignal; +} +interface LanguageModelExpectedInput { + type: LanguageModelMessageType; + languages?: string[]; +} +type LanguageModelPrompt = + | LanguageModelMessage[] + | LanguageModelMessageShorthand[] + | string; +type LanguageModelInitialPrompts = + | LanguageModelMessage[] + | LanguageModelMessageShorthand[]; +interface LanguageModelMessage { + role: LanguageModelMessageRole; + content: LanguageModelMessageContent[]; +} +interface LanguageModelMessageShorthand { + role: LanguageModelMessageRole; + content: string; +} +interface LanguageModelMessageContent { + type: LanguageModelMessageType; + content: LanguageModelMessageContentValue; +} +type LanguageModelMessageRole = 'system' | 'user' | 'assistant'; +type LanguageModelMessageType = 'text' | 'image' | 'audio'; +type LanguageModelMessageContentValue = + | ImageBitmapSource + | AudioBuffer + | BufferSource + | string; From 5302797ef4c046076dd9ea53449f94c8e4c19814 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Tue, 15 Apr 2025 16:45:36 -0700 Subject: [PATCH 18/28] Took dependency on new type --- packages/vertexai/src/types/language-model.ts | 4 ++-- packages/vertexai/src/types/requests.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/vertexai/src/types/language-model.ts b/packages/vertexai/src/types/language-model.ts index 5bfb38beea4..fa52cd9272e 100644 --- a/packages/vertexai/src/types/language-model.ts +++ b/packages/vertexai/src/types/language-model.ts @@ -38,12 +38,12 @@ enum Availability { 'downloading', 'available' } -interface LanguageModelCreateCoreOptions { +export interface LanguageModelCreateCoreOptions { topK?: number; temperature?: number; expectedInputs?: LanguageModelExpectedInput[]; } -interface LanguageModelCreateOptions extends LanguageModelCreateCoreOptions { +export interface LanguageModelCreateOptions extends LanguageModelCreateCoreOptions { signal?: AbortSignal; systemPrompt?: string; initialPrompts?: LanguageModelInitialPrompts; diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index 62d0c69a3ba..c32390519b3 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -24,6 +24,7 @@ import { HarmCategory } from './enums'; import { ObjectSchemaInterface, SchemaRequest } from './schema'; +import {LanguageModelCreateOptions} from '../types/language-model'; /** * Base parameters for a number of methods. @@ -225,7 +226,7 @@ export interface HybridParams { /** * Optional. Specifies advanced params for on-device inference. */ - onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; + onDeviceParams?: LanguageModelCreateOptions; /** * Optional. Specifies advanced params for in-cloud inference. */ From fe18abb9e115d683b14576604f66953c04627810 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Tue, 15 Apr 2025 17:13:10 -0700 Subject: [PATCH 19/28] docgen --- common/api-review/vertexai.api.md | 3 ++- docs-devsite/vertexai.hybridparams.md | 4 ++-- docs-devsite/vertexai.md | 10 +++++----- docs-devsite/vertexai.modelparams.md | 2 +- docs-devsite/vertexai.requestoptions.md | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index ef7d0b4f300..2286824d45c 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -421,7 +421,8 @@ export enum HarmSeverity { export interface HybridParams { inCloudParams?: ModelParams; mode: InferenceMode; - onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; + // Warning: (ae-forgotten-export) The symbol "LanguageModelCreateOptions" needs to be exported by the entry point index.d.ts + onDeviceParams?: LanguageModelCreateOptions; } // @beta diff --git a/docs-devsite/vertexai.hybridparams.md b/docs-devsite/vertexai.hybridparams.md index 912f5e43c36..cf847b40fa7 100644 --- a/docs-devsite/vertexai.hybridparams.md +++ b/docs-devsite/vertexai.hybridparams.md @@ -24,7 +24,7 @@ export interface HybridParams | --- | --- | --- | | [inCloudParams](./vertexai.hybridparams.md#hybridparamsincloudparams) | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Optional. Specifies advanced params for in-cloud inference. | | [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Specifies on-device or in-cloud inference. Defaults to prefer on-device. | -| [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | AILanguageModelCreateOptionsWithSystemPrompt | Optional. Specifies advanced params for on-device inference. | +| [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | LanguageModelCreateOptions | Optional. Specifies advanced params for on-device inference. | ## HybridParams.inCloudParams @@ -53,5 +53,5 @@ Optional. Specifies advanced params for on-device inference. Signature: ```typescript -onDeviceParams?: AILanguageModelCreateOptionsWithSystemPrompt; +onDeviceParams?: LanguageModelCreateOptions; ``` diff --git a/docs-devsite/vertexai.md b/docs-devsite/vertexai.md index 44ae7294735..3ad906c6e47 100644 --- a/docs-devsite/vertexai.md +++ b/docs-devsite/vertexai.md @@ -19,8 +19,8 @@ The Vertex AI in Firebase Web SDK. | function(app, ...) | | [getVertexAI(app, options)](./vertexai.md#getvertexai_04094cf) | Returns a [VertexAI](./vertexai.vertexai.md#vertexai_interface) instance for the given app. | | function(vertexAI, ...) | -| [getGenerativeModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getgenerativemodel_8dbc150) | Returns a [GenerativeModel](./vertexai.generativemodel.md#generativemodel_class) class with methods for inference and other functionality. | -| [getImagenModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getimagenmodel_812c375) | (Public Preview) Returns an [ImagenModel](./vertexai.imagenmodel.md#imagenmodel_class) class with methods for using Imagen.Only Imagen 3 models (named imagen-3.0-*) are supported. | +| [getGenerativeModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getgenerativemodel_8dbc150) | Returns a [GenerativeModel](./vertexai.generativemodel.md#generativemodel_class) class with methods for inference and other functionality. | +| [getImagenModel(vertexAI, modelParams, requestOptions)](./vertexai.md#getimagenmodel_812c375) | (Public Preview) Returns an [ImagenModel](./vertexai.imagenmodel.md#imagenmodel_class) class with methods for using Imagen.Only Imagen 3 models (named imagen-3.0-*) are supported. | ## Classes @@ -100,10 +100,10 @@ The Vertex AI in Firebase Web SDK. | [ImagenSafetySettings](./vertexai.imagensafetysettings.md#imagensafetysettings_interface) | (Public Preview) Settings for controlling the aggressiveness of filtering out sensitive content.See the [documentation](http://firebase.google.com/docs/vertex-ai/generate-images) for more details. | | [InlineDataPart](./vertexai.inlinedatapart.md#inlinedatapart_interface) | Content part interface if the part represents an image. | | [ModalityTokenCount](./vertexai.modalitytokencount.md#modalitytokencount_interface) | Represents token counting info for a single modality. | -| [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | -| [ObjectSchemaInterface](./vertexai.objectschemainterface.md#objectschemainterface_interface) | Interface for [ObjectSchema](./vertexai.objectschema.md#objectschema_class) class. | +| [ModelParams](./vertexai.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | +| [ObjectSchemaInterface](./vertexai.objectschemainterface.md#objectschemainterface_interface) | Interface for [ObjectSchema](./vertexai.objectschema.md#objectschema_class) class. | | [PromptFeedback](./vertexai.promptfeedback.md#promptfeedback_interface) | If the prompt was blocked, this will be populated with blockReason and the relevant safetyRatings. | -| [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | +| [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). | | [RetrievedContextAttribution](./vertexai.retrievedcontextattribution.md#retrievedcontextattribution_interface) | | | [SafetyRating](./vertexai.safetyrating.md#safetyrating_interface) | A safety rating associated with a [GenerateContentCandidate](./vertexai.generatecontentcandidate.md#generatecontentcandidate_interface) | | [SafetySetting](./vertexai.safetysetting.md#safetysetting_interface) | Safety setting that can be sent as part of request parameters. | diff --git a/docs-devsite/vertexai.modelparams.md b/docs-devsite/vertexai.modelparams.md index fe7b7d37c30..0776b198cf1 100644 --- a/docs-devsite/vertexai.modelparams.md +++ b/docs-devsite/vertexai.modelparams.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # ModelParams interface -Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). +Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). Signature: diff --git a/docs-devsite/vertexai.requestoptions.md b/docs-devsite/vertexai.requestoptions.md index 9e174c12a32..4e1ce2b86e3 100644 --- a/docs-devsite/vertexai.requestoptions.md +++ b/docs-devsite/vertexai.requestoptions.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # RequestOptions interface -Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). +Params passed to [getGenerativeModel()](./vertexai.md#getgenerativemodel_8dbc150). Signature: From 31a46a1f1decb0fa97b95a244fb2cf426d4d5b04 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Tue, 15 Apr 2025 17:24:32 -0700 Subject: [PATCH 20/28] post yarn format --- packages/vertexai/src/types/language-model.ts | 3 ++- packages/vertexai/src/types/requests.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/vertexai/src/types/language-model.ts b/packages/vertexai/src/types/language-model.ts index fa52cd9272e..e564ca467b4 100644 --- a/packages/vertexai/src/types/language-model.ts +++ b/packages/vertexai/src/types/language-model.ts @@ -43,7 +43,8 @@ export interface LanguageModelCreateCoreOptions { temperature?: number; expectedInputs?: LanguageModelExpectedInput[]; } -export interface LanguageModelCreateOptions extends LanguageModelCreateCoreOptions { +export interface LanguageModelCreateOptions + extends LanguageModelCreateCoreOptions { signal?: AbortSignal; systemPrompt?: string; initialPrompts?: LanguageModelInitialPrompts; diff --git a/packages/vertexai/src/types/requests.ts b/packages/vertexai/src/types/requests.ts index c32390519b3..82f023de467 100644 --- a/packages/vertexai/src/types/requests.ts +++ b/packages/vertexai/src/types/requests.ts @@ -24,7 +24,7 @@ import { HarmCategory } from './enums'; import { ObjectSchemaInterface, SchemaRequest } from './schema'; -import {LanguageModelCreateOptions} from '../types/language-model'; +import { LanguageModelCreateOptions } from '../types/language-model'; /** * Base parameters for a number of methods. From d0fb0a59571c29f22f2a939de9581663c0d10843 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 25 Mar 2025 09:30:30 -0700 Subject: [PATCH 21/28] Define ChromeAdapter class --- common/api-review/vertexai.api.md | 5 +- packages/vertexai/src/api.ts | 11 +- .../vertexai/src/methods/chat-session.test.ts | 19 ++- packages/vertexai/src/methods/chat-session.ts | 3 + .../vertexai/src/methods/chrome-adapter.ts | 30 ++++ .../src/methods/generate-content.test.ts | 60 +++++-- .../vertexai/src/methods/generate-content.ts | 27 ++- .../src/models/generative-model.test.ts | 147 ++++++++++------ .../vertexai/src/models/generative-model.ts | 4 + packages/vertexai/src/types/ai.ts | 161 ++++++++++++++++++ 10 files changed, 394 insertions(+), 73 deletions(-) create mode 100644 packages/vertexai/src/methods/chrome-adapter.ts create mode 100644 packages/vertexai/src/types/ai.ts diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 2286824d45c..f03e7ed14ed 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -42,7 +42,8 @@ export class BooleanSchema extends Schema { // @public export class ChatSession { // Warning: (ae-forgotten-export) The symbol "ApiSettings" needs to be exported by the entry point index.d.ts - constructor(apiSettings: ApiSettings, model: string, params?: StartChatParams | undefined, requestOptions?: RequestOptions | undefined); + // Warning: (ae-forgotten-export) The symbol "ChromeAdapter" needs to be exported by the entry point index.d.ts + constructor(apiSettings: ApiSettings, model: string, chromeAdapter: ChromeAdapter, params?: StartChatParams | undefined, requestOptions?: RequestOptions | undefined); getHistory(): Promise; // (undocumented) model: string; @@ -324,7 +325,7 @@ export interface GenerativeContentBlob { // @public export class GenerativeModel extends VertexAIModel { - constructor(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: RequestOptions); + constructor(vertexAI: VertexAI, modelParams: ModelParams, chromeAdapter: ChromeAdapter, requestOptions?: RequestOptions); countTokens(request: CountTokensRequest | string | Array): Promise; static DEFAULT_HYBRID_IN_CLOUD_MODEL: string; generateContent(request: GenerateContentRequest | string | Array): Promise; diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 2b8536dd89f..0e42cf418ae 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -30,6 +30,7 @@ import { } from './types'; import { VertexAIError } from './errors'; import { VertexAIModel, GenerativeModel, ImagenModel } from './models'; +import { ChromeAdapter } from './methods/chrome-adapter'; export { ChatSession } from './methods/chat-session'; export * from './requests/schema-builder'; @@ -91,7 +92,15 @@ export function getGenerativeModel( `Must provide a model name. Example: getGenerativeModel({ model: 'my-model-name' })` ); } - return new GenerativeModel(vertexAI, inCloudParams, requestOptions); + return new GenerativeModel( + vertexAI, + inCloudParams, + new ChromeAdapter( + hybridParams.mode, + hybridParams.onDeviceParams + ), + requestOptions + ); } /** diff --git a/packages/vertexai/src/methods/chat-session.test.ts b/packages/vertexai/src/methods/chat-session.test.ts index bd389a3d778..64f77f740f0 100644 --- a/packages/vertexai/src/methods/chat-session.test.ts +++ b/packages/vertexai/src/methods/chat-session.test.ts @@ -23,6 +23,7 @@ import * as generateContentMethods from './generate-content'; import { GenerateContentStreamResult } from '../types'; import { ChatSession } from './chat-session'; import { ApiSettings } from '../types/internal'; +import { ChromeAdapter } from './chrome-adapter'; use(sinonChai); use(chaiAsPromised); @@ -44,7 +45,11 @@ describe('ChatSession', () => { generateContentMethods, 'generateContent' ).rejects('generateContent failed'); - const chatSession = new ChatSession(fakeApiSettings, 'a-model'); + const chatSession = new ChatSession( + fakeApiSettings, + 'a-model', + new ChromeAdapter() + ); await expect(chatSession.sendMessage('hello')).to.be.rejected; expect(generateContentStub).to.be.calledWith( fakeApiSettings, @@ -61,7 +66,11 @@ describe('ChatSession', () => { generateContentMethods, 'generateContentStream' ).rejects('generateContentStream failed'); - const chatSession = new ChatSession(fakeApiSettings, 'a-model'); + const chatSession = new ChatSession( + fakeApiSettings, + 'a-model', + new ChromeAdapter() + ); await expect(chatSession.sendMessageStream('hello')).to.be.rejected; expect(generateContentStreamStub).to.be.calledWith( fakeApiSettings, @@ -80,7 +89,11 @@ describe('ChatSession', () => { generateContentMethods, 'generateContentStream' ).resolves({} as unknown as GenerateContentStreamResult); - const chatSession = new ChatSession(fakeApiSettings, 'a-model'); + const chatSession = new ChatSession( + fakeApiSettings, + 'a-model', + new ChromeAdapter() + ); await chatSession.sendMessageStream('hello'); expect(generateContentStreamStub).to.be.calledWith( fakeApiSettings, diff --git a/packages/vertexai/src/methods/chat-session.ts b/packages/vertexai/src/methods/chat-session.ts index 60794001e37..4188872cff7 100644 --- a/packages/vertexai/src/methods/chat-session.ts +++ b/packages/vertexai/src/methods/chat-session.ts @@ -30,6 +30,7 @@ import { validateChatHistory } from './chat-session-helpers'; import { generateContent, generateContentStream } from './generate-content'; import { ApiSettings } from '../types/internal'; import { logger } from '../logger'; +import { ChromeAdapter } from './chrome-adapter'; /** * Do not log a message for this error. @@ -50,6 +51,7 @@ export class ChatSession { constructor( apiSettings: ApiSettings, public model: string, + private chromeAdapter: ChromeAdapter, public params?: StartChatParams, public requestOptions?: RequestOptions ) { @@ -95,6 +97,7 @@ export class ChatSession { this._apiSettings, this.model, generateContentRequest, + this.chromeAdapter, this.requestOptions ) ) diff --git a/packages/vertexai/src/methods/chrome-adapter.ts b/packages/vertexai/src/methods/chrome-adapter.ts new file mode 100644 index 00000000000..41e43b3dcda --- /dev/null +++ b/packages/vertexai/src/methods/chrome-adapter.ts @@ -0,0 +1,30 @@ +import { + EnhancedGenerateContentResponse, + GenerateContentRequest, + InferenceMode +} from '../types'; +import { LanguageModelCreateOptions } from '../types/language-model'; + +/** + * Defines an inference "backend" that uses Chrome's on-device model, + * and encapsulates logic for detecting when on-device is possible. + */ +export class ChromeAdapter { + constructor( + private mode?: InferenceMode, + private onDeviceParams?: LanguageModelCreateOptions + ) {} + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async isAvailable(request: GenerateContentRequest): Promise { + return false; + } + async generateContentOnDevice( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + request: GenerateContentRequest + ): Promise { + return { + text: () => '', + functionCalls: () => undefined + }; + } +} diff --git a/packages/vertexai/src/methods/generate-content.test.ts b/packages/vertexai/src/methods/generate-content.test.ts index 1d15632f828..6a0fa3c07dd 100644 --- a/packages/vertexai/src/methods/generate-content.test.ts +++ b/packages/vertexai/src/methods/generate-content.test.ts @@ -30,6 +30,7 @@ import { } from '../types'; import { ApiSettings } from '../types/internal'; import { Task } from '../requests/request'; +import { ChromeAdapter } from './chrome-adapter'; use(sinonChai); use(chaiAsPromised); @@ -70,7 +71,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text()).to.include('Mountain View, California'); expect(makeRequestStub).to.be.calledWith( @@ -95,7 +97,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text()).to.include('Use Freshly Ground Coffee'); expect(result.response.text()).to.include('30 minutes of brewing'); @@ -118,7 +121,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.usageMetadata?.totalTokenCount).to.equal(1913); expect(result.response.usageMetadata?.candidatesTokenCount).to.equal(76); @@ -153,7 +157,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text()).to.include( 'Some information cited from an external source' @@ -180,7 +185,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text).to.throw('SAFETY'); expect(makeRequestStub).to.be.calledWith( @@ -202,7 +208,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text).to.throw('SAFETY'); expect(makeRequestStub).to.be.calledWith( @@ -224,7 +231,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text()).to.equal(''); expect(makeRequestStub).to.be.calledWith( @@ -246,7 +254,8 @@ describe('generateContent()', () => { const result = await generateContent( fakeApiSettings, 'model', - fakeRequestParams + fakeRequestParams, + new ChromeAdapter() ); expect(result.response.text()).to.include('Some text'); expect(makeRequestStub).to.be.calledWith( @@ -268,7 +277,12 @@ describe('generateContent()', () => { json: mockResponse.json } as Response); await expect( - generateContent(fakeApiSettings, 'model', fakeRequestParams) + generateContent( + fakeApiSettings, + 'model', + fakeRequestParams, + new ChromeAdapter() + ) ).to.be.rejectedWith(/400.*invalid argument/); expect(mockFetch).to.be.called; }); @@ -283,10 +297,36 @@ describe('generateContent()', () => { json: mockResponse.json } as Response); await expect( - generateContent(fakeApiSettings, 'model', fakeRequestParams) + generateContent( + fakeApiSettings, + 'model', + fakeRequestParams, + new ChromeAdapter() + ) ).to.be.rejectedWith( /firebasevertexai\.googleapis[\s\S]*my-project[\s\S]*api-not-enabled/ ); expect(mockFetch).to.be.called; }); + it('on-device', async () => { + const expectedText = 'hi'; + const chromeAdapter = new ChromeAdapter(); + const mockIsAvailable = stub(chromeAdapter, 'isAvailable').resolves(true); + const mockGenerateContent = stub( + chromeAdapter, + 'generateContentOnDevice' + ).resolves({ + text: () => expectedText, + functionCalls: () => undefined + }); + const result = await generateContent( + fakeApiSettings, + 'model', + fakeRequestParams, + chromeAdapter + ); + expect(result.response.text()).to.equal(expectedText); + expect(mockIsAvailable).to.be.called; + expect(mockGenerateContent).to.be.calledWith(fakeRequestParams); + }); }); diff --git a/packages/vertexai/src/methods/generate-content.ts b/packages/vertexai/src/methods/generate-content.ts index 0944b38016a..63745c47fae 100644 --- a/packages/vertexai/src/methods/generate-content.ts +++ b/packages/vertexai/src/methods/generate-content.ts @@ -16,6 +16,7 @@ */ import { + EnhancedGenerateContentResponse, GenerateContentRequest, GenerateContentResponse, GenerateContentResult, @@ -26,6 +27,7 @@ import { Task, makeRequest } from '../requests/request'; import { createEnhancedContentResponse } from '../requests/response-helpers'; import { processStream } from '../requests/stream-reader'; import { ApiSettings } from '../types/internal'; +import { ChromeAdapter } from './chrome-adapter'; export async function generateContentStream( apiSettings: ApiSettings, @@ -44,12 +46,12 @@ export async function generateContentStream( return processStream(response); } -export async function generateContent( +async function generateContentOnCloud( apiSettings: ApiSettings, model: string, params: GenerateContentRequest, requestOptions?: RequestOptions -): Promise { +): Promise { const response = await makeRequest( model, Task.GENERATE_CONTENT, @@ -60,6 +62,27 @@ export async function generateContent( ); const responseJson: GenerateContentResponse = await response.json(); const enhancedResponse = createEnhancedContentResponse(responseJson); + return enhancedResponse; +} + +export async function generateContent( + apiSettings: ApiSettings, + model: string, + params: GenerateContentRequest, + chromeAdapter: ChromeAdapter, + requestOptions?: RequestOptions +): Promise { + let enhancedResponse; + if (await chromeAdapter.isAvailable(params)) { + enhancedResponse = await chromeAdapter.generateContentOnDevice(params); + } else { + enhancedResponse = await generateContentOnCloud( + apiSettings, + model, + params, + requestOptions + ); + } return { response: enhancedResponse }; diff --git a/packages/vertexai/src/models/generative-model.test.ts b/packages/vertexai/src/models/generative-model.test.ts index 987f9b115e2..7fcae843347 100644 --- a/packages/vertexai/src/models/generative-model.test.ts +++ b/packages/vertexai/src/models/generative-model.test.ts @@ -21,6 +21,7 @@ import * as request from '../requests/request'; import { match, restore, stub } from 'sinon'; import { getMockResponse } from '../../test-utils/mock-response'; import sinonChai from 'sinon-chai'; +import { ChromeAdapter } from '../methods/chrome-adapter'; use(sinonChai); @@ -39,21 +40,27 @@ const fakeVertexAI: VertexAI = { describe('GenerativeModel', () => { it('passes params through to generateContent', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - tools: [ - { - functionDeclarations: [ - { - name: 'myfunc', - description: 'mydesc' - } - ] - } - ], - toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.NONE } }, - systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + tools: [ + { + functionDeclarations: [ + { + name: 'myfunc', + description: 'mydesc' + } + ] + } + ], + toolConfig: { + functionCallingConfig: { mode: FunctionCallingMode.NONE } + }, + systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } + }, + new ChromeAdapter() + ); expect(genModel.tools?.length).to.equal(1); expect(genModel.toolConfig?.functionCallingConfig?.mode).to.equal( FunctionCallingMode.NONE @@ -84,10 +91,14 @@ describe('GenerativeModel', () => { restore(); }); it('passes text-only systemInstruction through to generateContent', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - systemInstruction: 'be friendly' - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + systemInstruction: 'be friendly' + }, + new ChromeAdapter() + ); expect(genModel.systemInstruction?.parts[0].text).to.equal('be friendly'); const mockResponse = getMockResponse( 'vertexAI', @@ -110,21 +121,27 @@ describe('GenerativeModel', () => { restore(); }); it('generateContent overrides model values', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - tools: [ - { - functionDeclarations: [ - { - name: 'myfunc', - description: 'mydesc' - } - ] - } - ], - toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.NONE } }, - systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + tools: [ + { + functionDeclarations: [ + { + name: 'myfunc', + description: 'mydesc' + } + ] + } + ], + toolConfig: { + functionCallingConfig: { mode: FunctionCallingMode.NONE } + }, + systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } + }, + new ChromeAdapter() + ); expect(genModel.tools?.length).to.equal(1); expect(genModel.toolConfig?.functionCallingConfig?.mode).to.equal( FunctionCallingMode.NONE @@ -166,14 +183,20 @@ describe('GenerativeModel', () => { restore(); }); it('passes params through to chat.sendMessage', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - tools: [ - { functionDeclarations: [{ name: 'myfunc', description: 'mydesc' }] } - ], - toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.NONE } }, - systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + tools: [ + { functionDeclarations: [{ name: 'myfunc', description: 'mydesc' }] } + ], + toolConfig: { + functionCallingConfig: { mode: FunctionCallingMode.NONE } + }, + systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } + }, + new ChromeAdapter() + ); expect(genModel.tools?.length).to.equal(1); expect(genModel.toolConfig?.functionCallingConfig?.mode).to.equal( FunctionCallingMode.NONE @@ -204,10 +227,14 @@ describe('GenerativeModel', () => { restore(); }); it('passes text-only systemInstruction through to chat.sendMessage', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - systemInstruction: 'be friendly' - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + systemInstruction: 'be friendly' + }, + new ChromeAdapter() + ); expect(genModel.systemInstruction?.parts[0].text).to.equal('be friendly'); const mockResponse = getMockResponse( 'vertexAI', @@ -230,14 +257,20 @@ describe('GenerativeModel', () => { restore(); }); it('startChat overrides model values', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { - model: 'my-model', - tools: [ - { functionDeclarations: [{ name: 'myfunc', description: 'mydesc' }] } - ], - toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.NONE } }, - systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } - }); + const genModel = new GenerativeModel( + fakeVertexAI, + { + model: 'my-model', + tools: [ + { functionDeclarations: [{ name: 'myfunc', description: 'mydesc' }] } + ], + toolConfig: { + functionCallingConfig: { mode: FunctionCallingMode.NONE } + }, + systemInstruction: { role: 'system', parts: [{ text: 'be friendly' }] } + }, + new ChromeAdapter() + ); expect(genModel.tools?.length).to.equal(1); expect(genModel.toolConfig?.functionCallingConfig?.mode).to.equal( FunctionCallingMode.NONE @@ -282,7 +315,11 @@ describe('GenerativeModel', () => { restore(); }); it('calls countTokens', async () => { - const genModel = new GenerativeModel(fakeVertexAI, { model: 'my-model' }); + const genModel = new GenerativeModel( + fakeVertexAI, + { model: 'my-model' }, + new ChromeAdapter() + ); const mockResponse = getMockResponse( 'vertexAI', 'unary-success-total-tokens.json' diff --git a/packages/vertexai/src/models/generative-model.ts b/packages/vertexai/src/models/generative-model.ts index 32406ea19f7..c58eb3a1497 100644 --- a/packages/vertexai/src/models/generative-model.ts +++ b/packages/vertexai/src/models/generative-model.ts @@ -43,6 +43,7 @@ import { } from '../requests/request-helpers'; import { VertexAI } from '../public-types'; import { VertexAIModel } from './vertexai-model'; +import { ChromeAdapter } from '../methods/chrome-adapter'; /** * Class for generative model APIs. @@ -63,6 +64,7 @@ export class GenerativeModel extends VertexAIModel { constructor( vertexAI: VertexAI, modelParams: ModelParams, + private chromeAdapter: ChromeAdapter, requestOptions?: RequestOptions ) { super(vertexAI, modelParams.model); @@ -95,6 +97,7 @@ export class GenerativeModel extends VertexAIModel { systemInstruction: this.systemInstruction, ...formattedParams }, + this.chromeAdapter, this.requestOptions ); } @@ -132,6 +135,7 @@ export class GenerativeModel extends VertexAIModel { return new ChatSession( this._apiSettings, this.model, + this.chromeAdapter, { tools: this.tools, toolConfig: this.toolConfig, diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts new file mode 100644 index 00000000000..98a1e1d35bf --- /dev/null +++ b/packages/vertexai/src/types/ai.ts @@ -0,0 +1,161 @@ +/** + * Shims @types/dom-chromium-ai + * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. + */ +export interface AI { + readonly languageModel: AILanguageModelFactory; +} + +interface AICreateMonitor extends EventTarget { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ondownloadprogress: ((this: AICreateMonitor, ev: DownloadProgressEvent) => any) | null; + + addEventListener( + type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +interface DownloadProgressEvent extends Event { + readonly loaded: number; + readonly total: number; +} + +interface AICreateMonitorEventMap { + downloadprogress: DownloadProgressEvent; +} + +type AICreateMonitorCallback = (monitor: AICreateMonitor) => void; + +type AICapabilityAvailability = "readily" | "after-download" | "no"; + +// Language Model +// https://github.com/explainers-by-googlers/prompt-api/#full-api-surface-in-web-idl + +interface AILanguageModelFactory { + create( + options?: AILanguageModelCreateOptionsWithSystemPrompt | AILanguageModelCreateOptionsWithoutSystemPrompt, + ): Promise; + capabilities(): Promise; +} + +interface AILanguageModelCreateOptions { + signal?: AbortSignal; + monitor?: AICreateMonitorCallback; + + topK?: number; + temperature?: number; +} + +export interface AILanguageModelCreateOptionsWithSystemPrompt extends AILanguageModelCreateOptions { + systemPrompt?: string; + initialPrompts?: AILanguageModelPrompt[]; +} + +interface AILanguageModelCreateOptionsWithoutSystemPrompt extends AILanguageModelCreateOptions { + systemPrompt?: never; + initialPrompts?: + | [AILanguageModelSystemPrompt, ...AILanguageModelPrompt[]] + | AILanguageModelPrompt[]; +} + +type AILanguageModelPromptRole = "user" | "assistant"; +type AILanguageModelInitialPromptRole = "system" | AILanguageModelPromptRole; + +interface AILanguageModelPrompt { + role: AILanguageModelPromptRole; + content: string; +} + +interface AILanguageModelInitialPrompt { + role: AILanguageModelInitialPromptRole; + content: string; +} + +interface AILanguageModelSystemPrompt extends AILanguageModelInitialPrompt { + role: "system"; +} + +type AILanguageModelPromptInput = string | AILanguageModelPrompt | AILanguageModelPrompt[]; + +interface AILanguageModel extends EventTarget { + prompt(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; + promptStreaming(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): ReadableStream; + + countPromptTokens(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; + readonly maxTokens: number; + readonly tokensSoFar: number; + readonly tokensLeft: number; + + readonly topK: number; + readonly temperature: number; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + oncontextoverflow: ((this: AILanguageModel, ev: Event) => any) | null; + + addEventListener( + type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; + + clone(options?: AILanguageModelCloneOptions): Promise; + destroy(): void; +} + +interface AILanguageModelEventMap { + contextoverflow: Event; +} + +interface AILanguageModelPromptOptions { + signal?: AbortSignal; +} + +interface AILanguageModelCloneOptions { + signal?: AbortSignal; +} + +interface AILanguageModelCapabilities { + readonly available: AICapabilityAvailability; + languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; + + readonly defaultTopK: number | null; + readonly maxTopK: number | null; + readonly defaultTemperature: number | null; + readonly maxTemperature: number | null; +} From 77d0a708b72c3e024acbd58c25a3c83c659108eb Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 1 Apr 2025 17:44:30 -0700 Subject: [PATCH 22/28] Use type for inference mode and update docs --- docs-devsite/vertexai.hybridparams.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs-devsite/vertexai.hybridparams.md b/docs-devsite/vertexai.hybridparams.md index cf847b40fa7..1a75be4d01d 100644 --- a/docs-devsite/vertexai.hybridparams.md +++ b/docs-devsite/vertexai.hybridparams.md @@ -26,6 +26,7 @@ export interface HybridParams | [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Specifies on-device or in-cloud inference. Defaults to prefer on-device. | | [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | LanguageModelCreateOptions | Optional. Specifies advanced params for on-device inference. | + ## HybridParams.inCloudParams Optional. Specifies advanced params for in-cloud inference. From f31e32a9161687141b7e4b51923d0d686814ea9e Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 3 Apr 2025 13:43:54 -0700 Subject: [PATCH 23/28] Remove stray ai.ts --- packages/vertexai/src/types/ai.ts | 161 ------------------------------ 1 file changed, 161 deletions(-) delete mode 100644 packages/vertexai/src/types/ai.ts diff --git a/packages/vertexai/src/types/ai.ts b/packages/vertexai/src/types/ai.ts deleted file mode 100644 index 98a1e1d35bf..00000000000 --- a/packages/vertexai/src/types/ai.ts +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Shims @types/dom-chromium-ai - * TODO: replace with @types/dom-chromium-ai once we can use es2020.intl. - */ -export interface AI { - readonly languageModel: AILanguageModelFactory; -} - -interface AICreateMonitor extends EventTarget { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ondownloadprogress: ((this: AICreateMonitor, ev: DownloadProgressEvent) => any) | null; - - addEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, - options?: boolean | AddEventListenerOptions, - ): void; - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | AddEventListenerOptions, - ): void; - removeEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AICreateMonitor, ev: AICreateMonitorEventMap[K]) => any, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; -} - -interface DownloadProgressEvent extends Event { - readonly loaded: number; - readonly total: number; -} - -interface AICreateMonitorEventMap { - downloadprogress: DownloadProgressEvent; -} - -type AICreateMonitorCallback = (monitor: AICreateMonitor) => void; - -type AICapabilityAvailability = "readily" | "after-download" | "no"; - -// Language Model -// https://github.com/explainers-by-googlers/prompt-api/#full-api-surface-in-web-idl - -interface AILanguageModelFactory { - create( - options?: AILanguageModelCreateOptionsWithSystemPrompt | AILanguageModelCreateOptionsWithoutSystemPrompt, - ): Promise; - capabilities(): Promise; -} - -interface AILanguageModelCreateOptions { - signal?: AbortSignal; - monitor?: AICreateMonitorCallback; - - topK?: number; - temperature?: number; -} - -export interface AILanguageModelCreateOptionsWithSystemPrompt extends AILanguageModelCreateOptions { - systemPrompt?: string; - initialPrompts?: AILanguageModelPrompt[]; -} - -interface AILanguageModelCreateOptionsWithoutSystemPrompt extends AILanguageModelCreateOptions { - systemPrompt?: never; - initialPrompts?: - | [AILanguageModelSystemPrompt, ...AILanguageModelPrompt[]] - | AILanguageModelPrompt[]; -} - -type AILanguageModelPromptRole = "user" | "assistant"; -type AILanguageModelInitialPromptRole = "system" | AILanguageModelPromptRole; - -interface AILanguageModelPrompt { - role: AILanguageModelPromptRole; - content: string; -} - -interface AILanguageModelInitialPrompt { - role: AILanguageModelInitialPromptRole; - content: string; -} - -interface AILanguageModelSystemPrompt extends AILanguageModelInitialPrompt { - role: "system"; -} - -type AILanguageModelPromptInput = string | AILanguageModelPrompt | AILanguageModelPrompt[]; - -interface AILanguageModel extends EventTarget { - prompt(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; - promptStreaming(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): ReadableStream; - - countPromptTokens(input: AILanguageModelPromptInput, options?: AILanguageModelPromptOptions): Promise; - readonly maxTokens: number; - readonly tokensSoFar: number; - readonly tokensLeft: number; - - readonly topK: number; - readonly temperature: number; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - oncontextoverflow: ((this: AILanguageModel, ev: Event) => any) | null; - - addEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, - options?: boolean | AddEventListenerOptions, - ): void; - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | AddEventListenerOptions, - ): void; - removeEventListener( - type: K, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - listener: (this: AILanguageModel, ev: AILanguageModelEventMap[K]) => any, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; - - clone(options?: AILanguageModelCloneOptions): Promise; - destroy(): void; -} - -interface AILanguageModelEventMap { - contextoverflow: Event; -} - -interface AILanguageModelPromptOptions { - signal?: AbortSignal; -} - -interface AILanguageModelCloneOptions { - signal?: AbortSignal; -} - -interface AILanguageModelCapabilities { - readonly available: AICapabilityAvailability; - languageAvailable(languageTag: Intl.UnicodeBCP47LocaleIdentifier): AICapabilityAvailability; - - readonly defaultTopK: number | null; - readonly maxTopK: number | null; - readonly defaultTemperature: number | null; - readonly maxTemperature: number | null; -} From a7d482707141a7c20b9a165775ae47b627ac1f9f Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Thu, 3 Apr 2025 14:00:01 -0700 Subject: [PATCH 24/28] Run yarn format --- packages/vertexai/src/methods/chrome-adapter.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/vertexai/src/methods/chrome-adapter.ts b/packages/vertexai/src/methods/chrome-adapter.ts index 41e43b3dcda..21332969945 100644 --- a/packages/vertexai/src/methods/chrome-adapter.ts +++ b/packages/vertexai/src/methods/chrome-adapter.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2025 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 { EnhancedGenerateContentResponse, GenerateContentRequest, From 8975891fa002f10dcfa23b56e8d8cdd2e069f64a Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 8 Apr 2025 08:51:46 -0700 Subject: [PATCH 25/28] Update content generator to emulate Vertex response --- .../vertexai/src/methods/chrome-adapter.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/vertexai/src/methods/chrome-adapter.ts b/packages/vertexai/src/methods/chrome-adapter.ts index 21332969945..26ecd55c2da 100644 --- a/packages/vertexai/src/methods/chrome-adapter.ts +++ b/packages/vertexai/src/methods/chrome-adapter.ts @@ -15,11 +15,7 @@ * limitations under the License. */ -import { - EnhancedGenerateContentResponse, - GenerateContentRequest, - InferenceMode -} from '../types'; +import { GenerateContentRequest, InferenceMode } from '../types'; import { LanguageModelCreateOptions } from '../types/language-model'; /** @@ -38,10 +34,18 @@ export class ChromeAdapter { async generateContentOnDevice( // eslint-disable-next-line @typescript-eslint/no-unused-vars request: GenerateContentRequest - ): Promise { + ): Promise { return { - text: () => '', - functionCalls: () => undefined - }; + json: () => + Promise.resolve({ + candidates: [ + { + content: { + parts: [{ text: '' }] + } + } + ] + }) + } as Response; } } From ccf1d2b6605e4a701bde32fe9d5a61fc6c58f673 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Tue, 8 Apr 2025 14:59:18 -0700 Subject: [PATCH 26/28] Update tests to pass after refactor to Response --- .../src/methods/generate-content.test.ts | 19 +++++++++---------- .../vertexai/src/methods/generate-content.ts | 16 +++++++--------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/vertexai/src/methods/generate-content.test.ts b/packages/vertexai/src/methods/generate-content.test.ts index 6a0fa3c07dd..2a7699bf1d4 100644 --- a/packages/vertexai/src/methods/generate-content.test.ts +++ b/packages/vertexai/src/methods/generate-content.test.ts @@ -309,24 +309,23 @@ describe('generateContent()', () => { expect(mockFetch).to.be.called; }); it('on-device', async () => { - const expectedText = 'hi'; const chromeAdapter = new ChromeAdapter(); - const mockIsAvailable = stub(chromeAdapter, 'isAvailable').resolves(true); - const mockGenerateContent = stub( + const isAvailableStub = stub(chromeAdapter, 'isAvailable').resolves(true); + const mockResponse = getMockResponse( + 'unary-success-basic-reply-short.json' + ); + const generateContentStub = stub( chromeAdapter, 'generateContentOnDevice' - ).resolves({ - text: () => expectedText, - functionCalls: () => undefined - }); + ).resolves(mockResponse as Response); const result = await generateContent( fakeApiSettings, 'model', fakeRequestParams, chromeAdapter ); - expect(result.response.text()).to.equal(expectedText); - expect(mockIsAvailable).to.be.called; - expect(mockGenerateContent).to.be.calledWith(fakeRequestParams); + expect(result.response.text()).to.include('Mountain View, California'); + expect(isAvailableStub).to.be.called; + expect(generateContentStub).to.be.calledWith(fakeRequestParams); }); }); diff --git a/packages/vertexai/src/methods/generate-content.ts b/packages/vertexai/src/methods/generate-content.ts index 63745c47fae..ba7a162aa9c 100644 --- a/packages/vertexai/src/methods/generate-content.ts +++ b/packages/vertexai/src/methods/generate-content.ts @@ -16,7 +16,6 @@ */ import { - EnhancedGenerateContentResponse, GenerateContentRequest, GenerateContentResponse, GenerateContentResult, @@ -51,8 +50,8 @@ async function generateContentOnCloud( model: string, params: GenerateContentRequest, requestOptions?: RequestOptions -): Promise { - const response = await makeRequest( +): Promise { + return makeRequest( model, Task.GENERATE_CONTENT, apiSettings, @@ -60,9 +59,6 @@ async function generateContentOnCloud( JSON.stringify(params), requestOptions ); - const responseJson: GenerateContentResponse = await response.json(); - const enhancedResponse = createEnhancedContentResponse(responseJson); - return enhancedResponse; } export async function generateContent( @@ -72,17 +68,19 @@ export async function generateContent( chromeAdapter: ChromeAdapter, requestOptions?: RequestOptions ): Promise { - let enhancedResponse; + let response; if (await chromeAdapter.isAvailable(params)) { - enhancedResponse = await chromeAdapter.generateContentOnDevice(params); + response = await chromeAdapter.generateContentOnDevice(params); } else { - enhancedResponse = await generateContentOnCloud( + response = await generateContentOnCloud( apiSettings, model, params, requestOptions ); } + const responseJson: GenerateContentResponse = await response.json(); + const enhancedResponse = createEnhancedContentResponse(responseJson); return { response: enhancedResponse }; From bb75d91159163b092a1692a675e9d7b49ce8837e Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Wed, 16 Apr 2025 10:43:07 -0700 Subject: [PATCH 27/28] Inject LanguageModel provider --- packages/vertexai/src/api.ts | 2 ++ packages/vertexai/src/methods/chrome-adapter.ts | 6 +++++- packages/vertexai/src/methods/generate-content.test.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 0e42cf418ae..2f6de198608 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -31,6 +31,7 @@ import { import { VertexAIError } from './errors'; import { VertexAIModel, GenerativeModel, ImagenModel } from './models'; import { ChromeAdapter } from './methods/chrome-adapter'; +import { LanguageModel } from './types/language-model'; export { ChatSession } from './methods/chat-session'; export * from './requests/schema-builder'; @@ -96,6 +97,7 @@ export function getGenerativeModel( vertexAI, inCloudParams, new ChromeAdapter( + window.LanguageModel as LanguageModel, hybridParams.mode, hybridParams.onDeviceParams ), diff --git a/packages/vertexai/src/methods/chrome-adapter.ts b/packages/vertexai/src/methods/chrome-adapter.ts index 26ecd55c2da..a51b4060e26 100644 --- a/packages/vertexai/src/methods/chrome-adapter.ts +++ b/packages/vertexai/src/methods/chrome-adapter.ts @@ -16,7 +16,10 @@ */ import { GenerateContentRequest, InferenceMode } from '../types'; -import { LanguageModelCreateOptions } from '../types/language-model'; +import { + LanguageModel, + LanguageModelCreateOptions +} from '../types/language-model'; /** * Defines an inference "backend" that uses Chrome's on-device model, @@ -24,6 +27,7 @@ import { LanguageModelCreateOptions } from '../types/language-model'; */ export class ChromeAdapter { constructor( + private languageModelProvider?: LanguageModel, private mode?: InferenceMode, private onDeviceParams?: LanguageModelCreateOptions ) {} diff --git a/packages/vertexai/src/methods/generate-content.test.ts b/packages/vertexai/src/methods/generate-content.test.ts index 2a7699bf1d4..f714ec4d535 100644 --- a/packages/vertexai/src/methods/generate-content.test.ts +++ b/packages/vertexai/src/methods/generate-content.test.ts @@ -312,6 +312,7 @@ describe('generateContent()', () => { const chromeAdapter = new ChromeAdapter(); const isAvailableStub = stub(chromeAdapter, 'isAvailable').resolves(true); const mockResponse = getMockResponse( + 'vertexAI', 'unary-success-basic-reply-short.json' ); const generateContentStub = stub( From fadda5714d84144d1d7e8cc4a83a686dc8ecf986 Mon Sep 17 00:00:00 2001 From: Erik Eldridge Date: Wed, 16 Apr 2025 10:45:37 -0700 Subject: [PATCH 28/28] Run gendoc --- docs-devsite/vertexai.chatsession.md | 5 +++-- docs-devsite/vertexai.generativemodel.md | 5 +++-- docs-devsite/vertexai.hybridparams.md | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs-devsite/vertexai.chatsession.md b/docs-devsite/vertexai.chatsession.md index ed359f7e08c..c4a06206bfd 100644 --- a/docs-devsite/vertexai.chatsession.md +++ b/docs-devsite/vertexai.chatsession.md @@ -22,7 +22,7 @@ export declare class ChatSession | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(apiSettings, model, params, requestOptions)](./vertexai.chatsession.md#chatsessionconstructor) | | Constructs a new instance of the ChatSession class | +| [(constructor)(apiSettings, model, chromeAdapter, params, requestOptions)](./vertexai.chatsession.md#chatsessionconstructor) | | Constructs a new instance of the ChatSession class | ## Properties @@ -47,7 +47,7 @@ Constructs a new instance of the `ChatSession` class Signature: ```typescript -constructor(apiSettings: ApiSettings, model: string, params?: StartChatParams | undefined, requestOptions?: RequestOptions | undefined); +constructor(apiSettings: ApiSettings, model: string, chromeAdapter: ChromeAdapter, params?: StartChatParams | undefined, requestOptions?: RequestOptions | undefined); ``` #### Parameters @@ -56,6 +56,7 @@ constructor(apiSettings: ApiSettings, model: string, params?: StartChatParams | | --- | --- | --- | | apiSettings | ApiSettings | | | model | string | | +| chromeAdapter | ChromeAdapter | | | params | [StartChatParams](./vertexai.startchatparams.md#startchatparams_interface) \| undefined | | | requestOptions | [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) \| undefined | | diff --git a/docs-devsite/vertexai.generativemodel.md b/docs-devsite/vertexai.generativemodel.md index 831ec5d4369..978bacc612f 100644 --- a/docs-devsite/vertexai.generativemodel.md +++ b/docs-devsite/vertexai.generativemodel.md @@ -23,7 +23,7 @@ export declare class GenerativeModel extends VertexAIModel | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(vertexAI, modelParams, requestOptions)](./vertexai.generativemodel.md#generativemodelconstructor) | | Constructs a new instance of the GenerativeModel class | +| [(constructor)(vertexAI, modelParams, chromeAdapter, requestOptions)](./vertexai.generativemodel.md#generativemodelconstructor) | | Constructs a new instance of the GenerativeModel class | ## Properties @@ -53,7 +53,7 @@ Constructs a new instance of the `GenerativeModel` class Signature: ```typescript -constructor(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: RequestOptions); +constructor(vertexAI: VertexAI, modelParams: ModelParams, chromeAdapter: ChromeAdapter, requestOptions?: RequestOptions); ``` #### Parameters @@ -62,6 +62,7 @@ constructor(vertexAI: VertexAI, modelParams: ModelParams, requestOptions?: Reque | --- | --- | --- | | vertexAI | [VertexAI](./vertexai.vertexai.md#vertexai_interface) | | | modelParams | [ModelParams](./vertexai.modelparams.md#modelparams_interface) | | +| chromeAdapter | ChromeAdapter | | | requestOptions | [RequestOptions](./vertexai.requestoptions.md#requestoptions_interface) | | ## GenerativeModel.DEFAULT\_HYBRID\_IN\_CLOUD\_MODEL diff --git a/docs-devsite/vertexai.hybridparams.md b/docs-devsite/vertexai.hybridparams.md index 1a75be4d01d..cf847b40fa7 100644 --- a/docs-devsite/vertexai.hybridparams.md +++ b/docs-devsite/vertexai.hybridparams.md @@ -26,7 +26,6 @@ export interface HybridParams | [mode](./vertexai.hybridparams.md#hybridparamsmode) | [InferenceMode](./vertexai.md#inferencemode) | Specifies on-device or in-cloud inference. Defaults to prefer on-device. | | [onDeviceParams](./vertexai.hybridparams.md#hybridparamsondeviceparams) | LanguageModelCreateOptions | Optional. Specifies advanced params for on-device inference. | - ## HybridParams.inCloudParams Optional. Specifies advanced params for in-cloud inference.