Skip to content

Comments

feat: unify schema validation using jsonschema library#595

Open
GuyGoldenberg wants to merge 1 commit intogoogle:mainfrom
GuyGoldenberg:feat/unify-schema-validation
Open

feat: unify schema validation using jsonschema library#595
GuyGoldenberg wants to merge 1 commit intogoogle:mainfrom
GuyGoldenberg:feat/unify-schema-validation

Conversation

@GuyGoldenberg
Copy link

@GuyGoldenberg GuyGoldenberg commented Feb 23, 2026

Summary

Unifies schema validation by using the jsonschema library consistently across all tool types, adding enum validation support for AgentTool and output schemas.

Problem

FunctionTool used jsonschema.Resolved.Validate() which validates enums, but AgentTool and output schema used a custom ValidateMapOnSchema() that did not.

Solution

Add a genai.Schemajsonschema.Schema converter so all validation uses jsonschema.

Addresses TODO at agent/llmagent/llmagent.go:238.

Changes

  • Add internal/schemautil with converter functions
  • Update AgentTool and setModelResponseTool to use jsonschema validation
  • Remove unused internal/utils/schema_utils.go

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @GuyGoldenberg, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the schema validation logic within the ADK by standardizing on the jsonschema library. This change resolves inconsistencies arising from different tool types using disparate validation methods and specifically enhances AgentTool and output schema validation by adding crucial enum support. The introduction of a dedicated schemautil package centralizes the conversion from genai.Schema to jsonschema.Schema, leading to a more robust and consistent validation framework across the codebase.

Highlights

  • Unified Schema Validation: Schema validation across all tool types has been unified by consistently using the jsonschema library, replacing disparate validation methods.
  • Enhanced Validation Capabilities: Enum validation support has been added for AgentTool and output schemas, addressing a previously missing feature.
  • New Schema Utility Package: A new internal/schemautil package was created, containing GenaiToJSONSchema and GenaiToResolvedJSONSchema converter functions to facilitate the integration of genai.Schema with the jsonschema library.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • internal/llminternal/outputschema_processor.go
    • Updated setModelResponseTool.Run to use schemautil.GenaiToResolvedJSONSchema for output schema validation, replacing the custom utils.ValidateMapOnSchema.
  • internal/schemautil/convert.go
    • Added new file containing GenaiToJSONSchema and GenaiToResolvedJSONSchema functions for converting genai.Schema to jsonschema.Schema.
  • internal/schemautil/convert_test.go
    • Added new file with comprehensive tests for GenaiToJSONSchema and GenaiToResolvedJSONSchema, covering enum, basic types, properties, array, and numeric constraint validation.
  • internal/utils/schema_test.go
    • Removed the test file associated with the deprecated custom schema validation utility.
  • internal/utils/schema_utils.go
    • Removed the custom schema validation utility functions (matchType, ValidateMapOnSchema, ValidateOutputSchema).
  • tool/agenttool/agent_tool.go
    • Updated agentTool.Run to use schemautil.GenaiToResolvedJSONSchema for both agent input and output schema validation, replacing calls to utils.ValidateMapOnSchema and utils.ValidateOutputSchema.
Activity
  • No human activity (comments, reviews, etc.) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request successfully unifies schema validation across the ADK by leveraging the jsonschema library. This is a significant improvement that ensures consistent validation behavior, particularly for enums which were previously handled inconsistently. I have identified a critical bug in the schema converter regarding the interaction between Nullable and AnyOf fields, as well as some opportunities to improve performance by caching resolved schemas in hot paths.

Comment on lines 101 to 116
if gs.Nullable != nil && *gs.Nullable {
js.AnyOf = []*jsonschema.Schema{
{Type: strings.ToLower(string(gs.Type))},
{Type: "null"},
}
// Clear the main type when using AnyOf
js.Type = ""
}

// Convert AnyOf (recursive)
if len(gs.AnyOf) > 0 {
js.AnyOf = make([]*jsonschema.Schema, len(gs.AnyOf))
for i, s := range gs.AnyOf {
js.AnyOf[i] = GenaiToJSONSchema(s)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

There is a bug in the handling of Nullable and AnyOf. The current implementation of AnyOf (lines 111-116) completely overwrites the AnyOf slice created by the Nullable logic (lines 101-108). If a schema is both nullable and contains AnyOf, the nullability will be lost. The logic should be merged to ensure null is added to the AnyOf list if Nullable is true.

	// Convert AnyOf (recursive)
	if len(gs.AnyOf) > 0 {
		js.AnyOf = make([]*jsonschema.Schema, len(gs.AnyOf))
		for i, s := range gs.AnyOf {
			js.AnyOf[i] = GenaiToJSONSchema(s)
		}
	}

	// Handle Nullable via AnyOf with null type
	if gs.Nullable != nil && *gs.Nullable {
		if len(js.AnyOf) > 0 {
			js.AnyOf = append(js.AnyOf, &jsonschema.Schema{Type: "null"})
		} else {
			js.AnyOf = []*jsonschema.Schema{
				{Type: js.Type},
				{Type: "null"},
			}
		}
		// Clear the main type when using AnyOf for nullability
		js.Type = ""
	}

Comment on lines 33 to 39
js := &jsonschema.Schema{
Type: strings.ToLower(string(gs.Type)),
Description: gs.Description,
Title: gs.Title,
Pattern: gs.Pattern,
Required: gs.Required,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The converter is missing the Format field. JSON Schema supports formats like date-time, email, etc., which are often defined in genai.Schema and are useful for validation.

Suggested change
js := &jsonschema.Schema{
Type: strings.ToLower(string(gs.Type)),
Description: gs.Description,
Title: gs.Title,
Pattern: gs.Pattern,
Required: gs.Required,
}
js := &jsonschema.Schema{
Type: strings.ToLower(string(gs.Type)),
Format: gs.Format,
Description: gs.Description,
Title: gs.Title,
Pattern: gs.Pattern,
Required: gs.Required,
}

Comment on lines 49 to 55
// Convert numeric constraints
if gs.Minimum != nil {
js.Minimum = gs.Minimum
}
if gs.Maximum != nil {
js.Maximum = gs.Maximum
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The converter is missing the MultipleOf numeric constraint.

	// Convert numeric constraints
	if gs.Minimum != nil {
		js.Minimum = gs.Minimum
	}
	if gs.Maximum != nil {
		js.Maximum = gs.Maximum
	}
	if gs.MultipleOf != nil {
		js.MultipleOf = gs.MultipleOf
	}

Comment on lines 67 to 75
// Convert array constraints
if gs.MinItems != nil {
minItems := int(*gs.MinItems)
js.MinItems = &minItems
}
if gs.MaxItems != nil {
maxItems := int(*gs.MaxItems)
js.MaxItems = &maxItems
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The converter is missing the UniqueItems array constraint.

	// Convert array constraints
	if gs.MinItems != nil {
		minItems := int(*gs.MinItems)
		js.MinItems = &minItems
	}
	if gs.MaxItems != nil {
		maxItems := int(*gs.MaxItems)
		js.MaxItems = &maxItems
	}
	if gs.UniqueItems != nil {
		js.UniqueItems = *gs.UniqueItems
	}

var err error
if agentInputSchema != nil {
if err = utils.ValidateMapOnSchema(margs, agentInputSchema, true); err != nil {
resolved, resolveErr := schemautil.GenaiToResolvedJSONSchema(agentInputSchema)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Calling GenaiToResolvedJSONSchema inside the Run method is inefficient. This function performs a recursive conversion of the schema and then resolves (compiles) it, which is an expensive operation. Since the agent's input schema is typically static, it should be resolved once (e.g., during tool initialization or lazily cached) rather than on every execution.

if err := json.Unmarshal([]byte(outputText), &parsedOutput); err != nil {
return nil, fmt.Errorf("failed to parse output JSON for sub-agent %s: %w", t.agent.Name(), err)
}
resolved, resolveErr := schemautil.GenaiToResolvedJSONSchema(agentOutputSchema)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the input schema validation, resolving the output schema on every Run call is inefficient. Consider caching the resolved schema.

return nil, fmt.Errorf("unexpected args type for set_model_response: %T", args)
}
if err := utils.ValidateMapOnSchema(m, t.schema, false); err != nil {
resolved, err := schemautil.GenaiToResolvedJSONSchema(t.schema)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Resolving the output schema on every Run call is inefficient. Since setModelResponseTool is created per request in the processor, and the schema is derived from the agent's state, you should consider resolving the schema once and reusing it across invocations.

This change unifies schema validation across all tool types by using the
jsonschema library consistently, which properly validates enum values
and other schema constraints.

Previously, FunctionTool used jsonschema.Resolved.Validate() while
AgentTool and output schema validation used a custom ValidateMapOnSchema
function that lacked enum validation support.

Changes:
- Add internal/schemautil package with GenaiToJSONSchema converter
- Update AgentTool to use jsonschema validation
- Update setModelResponseTool to use jsonschema validation
- Remove unused custom validation functions from internal/utils

This aligns with the TODO at llmagent.go:238 to migrate toward jsonschema.
@GuyGoldenberg GuyGoldenberg force-pushed the feat/unify-schema-validation branch from 7ddaee1 to 734823a Compare February 23, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant