Skip to content

feat(go): Schema definition system with dotprompt #2793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Conversation

ihan211
Copy link

@ihan211 ihan211 commented Apr 22, 2025

This PR adds a schema definition system to genkit with Dotprompt reference support.
Key Components

Schema registration with Dotprompt framework
DefineSchema API for defining prompt data structures
Enhanced initialization process for schema registration
Schema resolution within templates

Example Usage

// Define a product schema
type ProductSchema struct {
Name string json:"name"
Description string json:"description"
Price float64 json:"price"
Category string json:"category"
InStock bool json:"inStock"
}

// Register the schema with genkit
genkit.DefineSchema("ProductSchema", ProductSchema{})

// Reference the schema in a Dotprompt template
// promptContent example:
// ---
// input:
// schema:
// theme: string
// output:
// schema: ProductSchema
// ---
// Generate a product that fits the {{theme}} theme.
// Make sure to provide a detailed description and appropriate pricing.

The implementation enables:

  • Automatic schema registration during Genkit initialization
  • Structured output parsing from model responses to Go structs
  • Schema reference resolution within Dotprompt templates
  • JSON Schema support for standardized type definitions

Testing
Unit tests in schema_test.go
Working example in samples directory

Checklist (if applicable):

ihan211 added 2 commits April 15, 2025 17:52
…d improve code organization

- Move pendingSchemas management to core package to avoid validation duplication
- Add RegisterGlobalSchemaResolver that follows DRY by calling registerSchemaResolver
- Create recursive helper function for field-to-schema conversion to support nested structs
- Fix import cycles between genkit, core, and registry packages
- Standardize schema path construction with consistent separators
- Add functions to retrieve and clear pending schemas
- Update schema registration during initialization process
- Fix LookupPrompt function signature to match usage

This refactoring addresses code review feedback by:
1. Eliminating duplicate validation between genkit.DefineSchema and core.RegisterSchema
2. Following DRY principle for schema resolver registration
3. Improving support for nested struct types with recursive field conversion
4. Creating a cleaner architecture with proper separation of concerns
@AbeJLazaro AbeJLazaro changed the title This PR adds a schema definition system to genkit with Dotprompt reference support. feat(go): Schema definition system with dotprompt Apr 22, 2025
Comment on lines 16 to 18
// Package core provides core functionality for the genkit framework.

package core
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Package core provides core functionality for the genkit framework.
package core
// Package core provides core functionality for the Genkit framework.
package core

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


// ClearSchemas removes all registered schemas.
// This is primarily for testing purposes.
func ClearSchemas() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's this function used in the framework? if it's for testing purposes, shouldn't this be defined as a helper function in a test file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to test file.

// Returns the schema for convenience in chaining operations.
func RegisterSchema(name string, schema any) Schema {
if name == "" {
panic("core.RegisterSchema: schema name cannot be empty")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can replace these panic() calls with errors since these are recoverable errors

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced.

@@ -245,6 +250,22 @@ func Init(ctx context.Context, opts ...GenkitOption) (*Genkit, error) {
return g, nil
}

// Internal function called during Init to register pending schemas
func registerPendingSchemas(reg *registry.Registry) error {
// Get pending schemas from core
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the code is pretty clear, we should avoid these kind of comments, same for line 264

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.

// personSchema := genkit.DefineSchema("Person", Person{})
func DefineSchema(name string, schema Schema) Schema {
if name == "" {
panic("genkit.DefineSchema: schema name cannot be empty")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not panic, these errors are recoverable. Try to return a (Schema, error) pair

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced.

return jsonSchema
}

// Register the resolver with Dotprompt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can ignore this comment, same for the one at line 112

schemaResolver := func(name string) any {
schema, exists := LookupSchema(name)
if !exists {
fmt.Printf("Schema '%s' not found in registry\n", name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use slog to log these kind of messages, here's an example of how it is used:

slog.Error("schema not found in registry", "name", name)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced


r.Dotprompt.DefineSchema(name, jsonSchema)
r.RegisterValue(SchemaType+"/"+name, structType)
fmt.Printf("Registered schema '%s' with registry and Dotprompt\n", name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these logs are not for debugging purposes, use slog instead, otherwise I think you should remove them

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.

}

// DumpRegistrySchemas prints all schemas stored in the registry
func (r *Registry) DumpRegistrySchemas() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find where this function is used, why is it needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.


// convertStructToJsonSchema converts a Go struct to a JSON schema
func convertStructToJsonSchema(structType any) (*jsonschema.Schema, error) {
fmt.Printf("Converting schema of type %T to JSON Schema\n", structType)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not needed, we can remove this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.

- Move ClearSchemas to schema_test.go as clearSchemasForTest()
- Replace panic with error returns in RegisterSchema and DefineSchema
- Improve logging using structured slog instead of fmt.Printf
- Remove debug prints and unused functions
- Add proper error handling for schema not found cases
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

3 participants