Skip to content

Commit 9639e0b

Browse files
Add gulf genkit validator (#314)
1 parent 6e472cf commit 9639e0b

18 files changed

+7636
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
.genkit
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Gemini Schema Validation Logic
2+
3+
This document outlines the validation rules that should be implemented in the `validateSchema` function. The purpose of this validator is to check for constraints that are not easily expressed in the JSON schema itself, such as conditional requirements and reference integrity.
4+
5+
Each message corresponds to one of the four message schemas: `stream_header.json`, `component_update.json`, `data_model_update.json`, or `begin_rendering.json`.
6+
7+
## `ComponentUpdate` Message Rules
8+
9+
### 1. Component ID Integrity
10+
11+
* **Uniqueness**: All component `id`s within the `components` array must be unique.
12+
* **Reference Validity**: Any property that references a component ID (e.g., `child`, `children`, `entryPointChild`, `contentChild`) must point to an ID that actually exists in the `components` array.
13+
14+
### 2. Component-Specific Property Rules
15+
16+
For each component in the `components` array, the following rules apply based on its `type`:
17+
18+
* **General**:
19+
* A component must have an `id` and a `type`.
20+
21+
* **Value Components** (`Heading`, `Text`, `Image`, `Video`, `AudioPlayer`, `TextField`, `CheckBox`, `DateTimeInput`, `MultipleChoice`, `Slider`):
22+
* **Required**: Must have a `value` property.
23+
24+
* **Container Components** (`Row`, `Column`, `List`):
25+
* **Required**: Must have a `children` property.
26+
* The `children` object must contain *either* `explicitList` *or* `template`, but not both.
27+
28+
* **Card**:
29+
* **Required**: Must have a `child` property.
30+
31+
* **Tabs**:
32+
* **Required**: Must have a `tabItems` property, which must be an array.
33+
* Each item in `tabItems` must have a `title` and a `child`.
34+
35+
* **Modal**:
36+
* **Required**: Must have both `entryPointChild` and `contentChild` properties.
37+
38+
* **Button**:
39+
* **Required**: Must have `label` and `action` properties.
40+
41+
* **CheckBox**:
42+
* **Required**: Must have `label` and `value` properties.
43+
44+
## `DataModelUpdate` Message Rules
45+
46+
* **Path and Contents**: A `DataModelUpdate` message must have a `contents` property. The `path` property is optional.
47+
* If `path` is not present, the `contents` object will replace the entire data model.
48+
* If `path` is present, the `contents` will be set at that location in the data model.
49+
50+
## `BeginRendering` Message Rules
51+
52+
* **Root Presence**: Must have a `root` property.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Genkit Flow
2+
3+
To run the flow, use the following command:
4+
5+
```bash
6+
npx tsx src/index.ts
7+
```
8+
9+
## Running a Single Test
10+
11+
You can run the script for a single model and data point by using the `--model` and `--prompt` command-line flags. This is useful for quick tests and debugging.
12+
13+
### Syntax
14+
15+
```bash
16+
npx tsx src/index.ts --model='<model_name>' --prompt=<prompt_name>
17+
```
18+
19+
### Example
20+
21+
To run the test with the `gpt-5-nano (reasoning: minimal)` model and the `generateDogUIs` prompt, use the following command:
22+
23+
```bash
24+
npx tsx src/index.ts --model='gpt-5-nano (reasoning: minimal)' --prompt=generateDogUIs
25+
```
26+
27+
## Controlling Output
28+
29+
By default, the script only prints the summary table and any errors that occur during generation. To see the full JSON output for each successful generation, use the `--verbose` flag.
30+
31+
### Example
32+
33+
```bash
34+
npx tsx src/index.ts --verbose
35+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { googleAI } from '@genkit-ai/google-genai';
2+
import { configure } from 'genkit';
3+
4+
export default configure({
5+
plugins: [
6+
googleAI(),
7+
],
8+
logLevel: 'debug',
9+
enableTracingAndMetrics: true,
10+
});
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"use strict";
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
var desc = Object.getOwnPropertyDescriptor(m, k);
5+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6+
desc = { enumerable: true, get: function() { return m[k]; } };
7+
}
8+
Object.defineProperty(o, k2, desc);
9+
}) : (function(o, m, k, k2) {
10+
if (k2 === undefined) k2 = k;
11+
o[k2] = m[k];
12+
}));
13+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14+
Object.defineProperty(o, "default", { enumerable: true, value: v });
15+
}) : function(o, v) {
16+
o["default"] = v;
17+
});
18+
var __importStar = (this && this.__importStar) || (function () {
19+
var ownKeys = function(o) {
20+
ownKeys = Object.getOwnPropertyNames || function (o) {
21+
var ar = [];
22+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23+
return ar;
24+
};
25+
return ownKeys(o);
26+
};
27+
return function (mod) {
28+
if (mod && mod.__esModule) return mod;
29+
var result = {};
30+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31+
__setModuleDefault(result, mod);
32+
return result;
33+
};
34+
})();
35+
Object.defineProperty(exports, "__esModule", { value: true });
36+
exports.componentGeneratorFlow = void 0;
37+
const google_genai_1 = require("@genkit-ai/google-genai");
38+
const genkit_1 = require("genkit");
39+
const fs = __importStar(require("fs"));
40+
const path = __importStar(require("path"));
41+
const openai_1 = require("@genkit-ai/compat-oai/openai");
42+
const genkitx_anthropic_1 = require("genkitx-anthropic");
43+
// Read the schema file
44+
const schemaString = fs.readFileSync(path.join(__dirname, 'schema.json'), 'utf-8');
45+
const schema = JSON.parse(schemaString);
46+
const ai = (0, genkit_1.genkit)({
47+
plugins: [(0, google_genai_1.googleAI)({ apiKey: process.env.GEMINI_API_KEY }), (0, openai_1.openAI)(), (0, genkitx_anthropic_1.anthropic)({ apiKey: process.env.ANTHROPIC_API_KEY }),],
48+
});
49+
// Define a UI component generator flow
50+
exports.componentGeneratorFlow = ai.defineFlow({
51+
name: 'componentGeneratorFlow',
52+
inputSchema: genkit_1.z.object({ prompt: genkit_1.z.string(), model: genkit_1.z.any() }),
53+
outputSchema: genkit_1.z.any(),
54+
}, async ({ prompt, model }) => {
55+
// Generate structured component data using the schema from the file
56+
const { output } = await ai.generate({
57+
prompt,
58+
model,
59+
output: { jsonSchema: schema },
60+
// config: {
61+
// thinkingConfig: { thinkingBudget: 0 }
62+
// },
63+
});
64+
if (!output)
65+
throw new Error('Failed to generate component');
66+
return output;
67+
});
68+
// Run the flow
69+
async function main() {
70+
const models = [
71+
openai_1.openAI.model('gpt-5-mini'),
72+
openai_1.openAI.model('gpt-5'),
73+
openai_1.openAI.model('gpt-5-nano'),
74+
google_genai_1.googleAI.model('gemini-2.5-flash'),
75+
google_genai_1.googleAI.model('gemini-2.5-flash-lite'),
76+
genkitx_anthropic_1.claude4Sonnet,
77+
genkitx_anthropic_1.claude35Haiku,
78+
];
79+
const prompt = `Generate a JSON conforming to the schema to describe the following UI:
80+
81+
A root node has already been created with ID "root". You need to create a ComponentUpdate message now.
82+
83+
A vertical list with:
84+
Dog breed information
85+
Dog generator
86+
87+
The dog breed information is a card, which contains a title “Famous Dog breeds”, a header image, and a carousel of different dog breeds. The carousel information should be in the data model at /carousel.
88+
89+
The dog generator is another card which is a form that generates a fictional dog breed with a description
90+
- Title
91+
- Description text explaining what it is
92+
- Dog breed name (text input)
93+
- Number of legs (number input)
94+
- Skills (checkboxes)
95+
- Button called “Generate” which takes the data above and generates a new dog description
96+
- A divider
97+
- A section which shows the generated content
98+
`;
99+
for (const model of models) {
100+
console.log(`Generating component with model: ${model.name}`);
101+
const component = await (0, exports.componentGeneratorFlow)({
102+
prompt,
103+
model,
104+
});
105+
console.log(JSON.stringify(component, null, 2));
106+
}
107+
}
108+
main().catch(console.error);

0 commit comments

Comments
 (0)