@genkit-ai/dotprompt
Version:
Genkit AI framework `.prompt` file format and management library.
201 lines (198 loc) • 5.88 kB
text/typescript
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MessageData } from '@genkit-ai/ai/model';
import { DocumentData } from '@genkit-ai/ai/retriever';
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { compile } from '../src/template';
describe('compile', () => {
for (const test of [
{
should: 'inject variables',
template: 'Hello {{name}}',
input: { name: 'World' },
want: [{ role: 'user', content: [{ text: 'Hello World' }] }],
},
{
should: 'allow multipart with url',
template: '{{media url=image}} Describe the image above.',
input: { image: 'https://some.image.url/image.jpg' },
want: [
{
role: 'user',
content: [
{ media: { url: 'https://some.image.url/image.jpg' } },
{ text: ' Describe the image above.' },
],
},
],
},
{
should: 'allow multiple media parts, adjacent or separated by text',
template:
'Look at these images: {{#each images}}{{media url=.}} {{/each}} Do you like them? Here ' +
'is another: {{media url=anotherImage}}',
input: {
images: [
'http://1.png',
'https://2.png',
'data:image/jpeg;base64,abc123',
],
anotherImage: 'http://anotherImage.png',
},
want: [
{
role: 'user',
content: [
{
text: 'Look at these images: ',
},
{
media: { url: 'http://1.png' },
},
{
media: { url: 'https://2.png' },
},
{
media: { url: 'data:image/jpeg;base64,abc123' },
},
{
text: ' Do you like them? Here is another: ',
},
{
media: { url: 'http://anotherImage.png' },
},
],
},
],
},
{
should: 'allow changing the role at the beginning',
template: ` {{role "system"}}You are super helpful.
{{~role "user"}}Do something!`,
want: [
{
role: 'system',
content: [{ text: 'You are super helpful.' }],
},
{
role: 'user',
content: [{ text: 'Do something!' }],
},
],
},
{
should: 'allow rendering JSON',
input: { test: true },
template: '{{json .}}',
want: [{ role: 'user', content: [{ text: '{"test":true}' }] }],
},
{
should: 'allow indenting JSON',
input: { test: true },
template: '{{json . indent=2}}',
want: [{ role: 'user', content: [{ text: '{\n "test": true\n}' }] }],
},
{
should: 'insert history after other messages before final user message',
input: {},
template: `{{role "system"}}You are a robot{{role "user"}}Hello there`,
options: {
history: [
{ role: 'user', content: [{ text: 'Ping' }] },
{ role: 'model', content: [{ text: 'Pong' }] },
],
},
want: [
{ role: 'system', content: [{ text: 'You are a robot' }] },
{ role: 'user', content: [{ text: 'Ping' }] },
{ role: 'model', content: [{ text: 'Pong' }] },
{ role: 'user', content: [{ text: 'Hello there' }] },
],
},
{
should: 'insert history in the specified location',
input: {},
template: `{{history}}{{role "system"}}You are a robot{{role "user"}}Hello there`,
options: {
history: [
{ role: 'user', content: [{ text: 'Ping' }] },
{ role: 'model', content: [{ text: 'Pong' }] },
],
},
want: [
{
role: 'user',
content: [{ text: 'Ping' }],
metadata: { purpose: 'history' },
},
{
role: 'model',
content: [{ text: 'Pong' }],
metadata: { purpose: 'history' },
},
{ role: 'system', content: [{ text: 'You are a robot' }] },
{ role: 'user', content: [{ text: 'Hello there' }] },
],
},
{
should: 'insert a blank context section when helper provided',
input: {},
template: `before{{section "context"}}after`,
options: {
context: [{ content: [{ text: 'doc content' }] }],
},
want: [
{
role: 'user',
content: [
{ text: 'before' },
{ metadata: { purpose: 'context', pending: true } },
{ text: 'after' },
],
},
],
},
{
should: 'insert a blank output section when helper provided',
input: {},
template: `before{{section "output"}}after`,
options: {
context: [{ content: [{ text: 'doc content' }] }],
},
want: [
{
role: 'user',
content: [
{ text: 'before' },
{ metadata: { purpose: 'output', pending: true } },
{ text: 'after' },
],
},
],
},
]) {
it(test.should, () => {
assert.deepEqual(
compile(test.template, { model: 'test/example' })(test.input, {
history: test.options?.history as MessageData[],
context: test.options?.context as DocumentData[],
}),
test.want
);
});
}
});