Skip to content

Commit 827bce3

Browse files
committed
Add test for generateContentStream
1 parent 98b0e22 commit 827bce3

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

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

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ describe('ChromeAdapter', () => {
407407
]
408408
});
409409
});
410-
it('honors response constraint', async () => {
410+
it('supports structured output by mapping responseSchema to responseConstraint', async () => {
411411
const languageModel = {
412412
// eslint-disable-next-line @typescript-eslint/no-unused-vars
413413
prompt: (p: LanguageModelMessageContent[]) => Promise.resolve('')
@@ -430,7 +430,7 @@ describe('ChromeAdapter', () => {
430430
},
431431
contents: [{ role: 'user', parts: [{ text: 'anything' }] }]
432432
} as GenerateContentRequest;
433-
const response = await adapter.generateContent(request);
433+
await adapter.generateContent(request);
434434
expect(promptStub).to.have.been.calledOnceWith(
435435
[
436436
{
@@ -442,15 +442,6 @@ describe('ChromeAdapter', () => {
442442
responseConstraint: responseSchema
443443
}
444444
);
445-
expect(await response.json()).to.deep.equal({
446-
candidates: [
447-
{
448-
content: {
449-
parts: [{ text: promptOutput }]
450-
}
451-
}
452-
]
453-
});
454445
});
455446
});
456447
describe('countTokens', () => {
@@ -592,6 +583,43 @@ describe('ChromeAdapter', () => {
592583
`data: {"candidates":[{"content":{"role":"model","parts":[{"text":["${part}"]}]}}]}\n\n`
593584
]);
594585
});
586+
it('supports structured output by mapping responseSchema to responseConstraint', async () => {
587+
const languageModel = {
588+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
589+
promptStreaming: p => new ReadableStream()
590+
} as LanguageModel;
591+
const languageModelProvider = {
592+
create: () => Promise.resolve(languageModel)
593+
} as LanguageModel;
594+
const promptStub = stub(languageModel, 'promptStreaming').returns(
595+
new ReadableStream()
596+
);
597+
const adapter = new ChromeAdapter(
598+
languageModelProvider,
599+
'prefer_on_device'
600+
);
601+
const responseSchema = Schema.object({
602+
properties: {}
603+
});
604+
const request = {
605+
generationConfig: {
606+
responseSchema
607+
},
608+
contents: [{ role: 'user', parts: [{ text: 'anything' }] }]
609+
} as GenerateContentRequest;
610+
await adapter.generateContentStream(request);
611+
expect(promptStub).to.have.been.calledOnceWith(
612+
[
613+
{
614+
type: 'text',
615+
content: request.contents[0].parts[0].text
616+
}
617+
],
618+
{
619+
responseConstraint: responseSchema
620+
}
621+
);
622+
});
595623
});
596624
});
597625

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

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,27 +107,16 @@ export class ChromeAdapter {
107107
*/
108108
async generateContent(request: GenerateContentRequest): Promise<Response> {
109109
const session = await this.createSession();
110-
111110
// TODO: support multiple content objects when Chrome supports
112111
// sequence<LanguageModelMessage>
113112
const contents = await Promise.all(
114113
request.contents[0].parts.map(ChromeAdapter.toLanguageModelMessageContent)
115114
);
116-
117115
const options = ChromeAdapter.extractLanguageModelPromptOptions(request);
118-
119116
const text = await session.prompt(contents, options);
120117
return ChromeAdapter.toResponse(text);
121118
}
122119

123-
private static extractLanguageModelPromptOptions(
124-
request: GenerateContentRequest
125-
): LanguageModelPromptOptions {
126-
return {
127-
responseConstraint: request.generationConfig?.responseSchema
128-
};
129-
}
130-
131120
/**
132121
* Generates content stream on device.
133122
*
@@ -145,7 +134,8 @@ export class ChromeAdapter {
145134
const contents = await Promise.all(
146135
request.contents[0].parts.map(ChromeAdapter.toLanguageModelMessageContent)
147136
);
148-
const stream = await session.promptStreaming(contents);
137+
const options = ChromeAdapter.extractLanguageModelPromptOptions(request);
138+
const stream = await session.promptStreaming(contents, options);
149139
return ChromeAdapter.toStreamResponse(stream);
150140
}
151141

@@ -286,6 +276,18 @@ export class ChromeAdapter {
286276
return newSession;
287277
}
288278

279+
/**
280+
* Extracts fields in common between {@link GenerateContentRequest} and
281+
* {@link LanguageModelPromptOptions}.
282+
*/
283+
private static extractLanguageModelPromptOptions(
284+
request: GenerateContentRequest
285+
): LanguageModelPromptOptions {
286+
return {
287+
responseConstraint: request.generationConfig?.responseSchema
288+
};
289+
}
290+
289291
private addImageTypeAsExpectedInput(): void {
290292
// Defaults to support image inputs for convenience.
291293
this.onDeviceParams.expectedInputs ??= [{ type: 'image' }];

0 commit comments

Comments
 (0)