Skip to content

Commit e814bf9

Browse files
committed
Assert options extracted in availability and generate content paths
1 parent e002c40 commit e814bf9

File tree

2 files changed

+47
-50
lines changed

2 files changed

+47
-50
lines changed

packages/ai/src/methods/chrome-adapter.test.ts

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,6 @@ async function toStringArray(
5454

5555
describe('ChromeAdapter', () => {
5656
describe('constructor', () => {
57-
it('determines expected inputs by request inspection', async () => {
58-
const languageModelProvider = {
59-
availability: () => Promise.resolve(Availability.available)
60-
} as LanguageModel;
61-
const availabilityStub = stub(
62-
languageModelProvider,
63-
'availability'
64-
).resolves(Availability.available);
65-
const adapter = new ChromeAdapter(
66-
languageModelProvider,
67-
'prefer_on_device'
68-
);
69-
await adapter.isAvailable({
70-
contents: [
71-
{
72-
role: 'user',
73-
parts: [
74-
{ text: 'hi' },
75-
// Triggers image as expected type.
76-
{ inlineData: { mimeType: 'image/jpeg', data: 'asd' } }
77-
]
78-
}
79-
]
80-
});
81-
expect(availabilityStub).to.have.been.calledWith({
82-
expectedInputs: [{ type: 'image' }]
83-
});
84-
});
8557
it('honors explicitly set expected inputs', async () => {
8658
const languageModelProvider = {
8759
availability: () => Promise.resolve(Availability.available)
@@ -303,6 +275,34 @@ describe('ChromeAdapter', () => {
303275
})
304276
).to.be.false;
305277
});
278+
it('extracts expected inputs from the request', async () => {
279+
const languageModelProvider = {
280+
availability: () => Promise.resolve(Availability.available)
281+
} as LanguageModel;
282+
const availabilityStub = stub(
283+
languageModelProvider,
284+
'availability'
285+
).resolves(Availability.available);
286+
const adapter = new ChromeAdapter(
287+
languageModelProvider,
288+
'prefer_on_device'
289+
);
290+
await adapter.isAvailable({
291+
contents: [
292+
{
293+
role: 'user',
294+
parts: [
295+
{ text: 'hi' },
296+
// Triggers image as expected type.
297+
{ inlineData: { mimeType: 'image/jpeg', data: 'asd' } }
298+
]
299+
}
300+
]
301+
});
302+
expect(availabilityStub).to.have.been.calledWith({
303+
expectedInputs: [{ type: 'image' }]
304+
});
305+
});
306306
});
307307
describe('generateContent', () => {
308308
it('throws if Chrome API is undefined', async () => {
@@ -382,14 +382,9 @@ describe('ChromeAdapter', () => {
382382
);
383383
const promptOutput = 'hi';
384384
const promptStub = stub(languageModel, 'prompt').resolves(promptOutput);
385-
const createOptions = {
386-
systemPrompt: 'be yourself',
387-
expectedInputs: [{ type: 'image' }]
388-
} as LanguageModelCreateOptions;
389385
const adapter = new ChromeAdapter(
390386
languageModelProvider,
391-
'prefer_on_device',
392-
{ createOptions }
387+
'prefer_on_device'
393388
);
394389
const request = {
395390
contents: [
@@ -409,7 +404,9 @@ describe('ChromeAdapter', () => {
409404
} as GenerateContentRequest;
410405
const response = await adapter.generateContent(request);
411406
// Asserts initialization params are proxied.
412-
expect(createStub).to.have.been.calledOnceWith(createOptions);
407+
expect(createStub).to.have.been.calledOnceWith({
408+
expectedInputs: [{ type: 'image' }]
409+
});
413410
// Asserts Vertex input type is mapped to Chrome type.
414411
expect(promptStub).to.have.been.calledOnceWith([
415412
{
@@ -610,13 +607,9 @@ describe('ChromeAdapter', () => {
610607
}
611608
})
612609
);
613-
const createOptions = {
614-
expectedInputs: [{ type: 'image' }]
615-
} as LanguageModelCreateOptions;
616610
const adapter = new ChromeAdapter(
617611
languageModelProvider,
618-
'prefer_on_device',
619-
{ createOptions }
612+
'prefer_on_device'
620613
);
621614
const request = {
622615
contents: [
@@ -635,7 +628,9 @@ describe('ChromeAdapter', () => {
635628
]
636629
} as GenerateContentRequest;
637630
const response = await adapter.generateContentStream(request);
638-
expect(createStub).to.have.been.calledOnceWith(createOptions);
631+
expect(createStub).to.have.been.calledOnceWith({
632+
expectedInputs: [{ type: 'image' }]
633+
});
639634
expect(promptStub).to.have.been.calledOnceWith([
640635
{
641636
role: request.contents[0].role,

packages/ai/src/methods/chrome-adapter.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ export class ChromeAdapter {
8484
return false;
8585
}
8686

87-
const requestOptions = this.inferCreateOptions(request);
88-
const mergedOptions = this.mergeCreateOptions(requestOptions);
87+
const extractedOptions = this.extractCreateOptions(request);
88+
const mergedOptions = this.mergeCreateOptions(extractedOptions);
8989

9090
// Triggers out-of-band download so model will eventually become available.
9191
const availability = await this.downloadIfAvailable(mergedOptions);
@@ -120,8 +120,8 @@ export class ChromeAdapter {
120120
* @returns {@link Response}, so we can reuse common response formatting.
121121
*/
122122
async generateContent(request: GenerateContentRequest): Promise<Response> {
123-
const requestOptions = this.inferCreateOptions(request);
124-
const mergedOptions = this.mergeCreateOptions(requestOptions);
123+
const extractedOptions = this.extractCreateOptions(request);
124+
const mergedOptions = this.mergeCreateOptions(extractedOptions);
125125
const session = await this.createSession(mergedOptions);
126126
const contents = await Promise.all(
127127
request.contents.map(ChromeAdapter.toLanguageModelMessage)
@@ -144,8 +144,8 @@ export class ChromeAdapter {
144144
async generateContentStream(
145145
request: GenerateContentRequest
146146
): Promise<Response> {
147-
const inferredOptions = this.inferCreateOptions(request);
148-
const mergedOptions = this.mergeCreateOptions(inferredOptions);
147+
const extractedOptions = this.extractCreateOptions(request);
148+
const mergedOptions = this.mergeCreateOptions(extractedOptions);
149149
const session = await this.createSession(mergedOptions);
150150
const contents = await Promise.all(
151151
request.contents.map(ChromeAdapter.toLanguageModelMessage)
@@ -165,16 +165,18 @@ export class ChromeAdapter {
165165
}
166166

167167
/**
168-
* Maps
168+
* Extracts session creation options specified at request-time.
169+
*
170+
* <p>In particular, this method maps
169171
* <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#blob">
170172
* Vertex's input mime types</a> to
171173
* <a href="https://github.com/webmachinelearning/prompt-api?tab=readme-ov-file#full-api-surface-in-web-idl">
172-
* Chrome's expected input types</a>.
174+
* Chrome's expected input types</a>.</p>
173175
*
174176
* <p>Chrome's API checks availability by type. It's tedious to specify the types in advance, so
175177
* this method infers the types.</p>
176178
*/
177-
private inferCreateOptions(
179+
private extractCreateOptions(
178180
request: GenerateContentRequest
179181
): LanguageModelCreateOptions {
180182
const inputSet = new Set<LanguageModelExpected>();

0 commit comments

Comments
 (0)