From 88b6f8ed9f4eda4100de00b88eedac533be319aa Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Thu, 5 Jun 2025 11:10:27 -0700 Subject: [PATCH 1/6] adding support for extra schema properties and the anyOf schema --- firebase-ai/CHANGELOG.md | 2 + .../com/google/firebase/ai/type/Schema.kt | 131 +++++++++++++++--- 2 files changed, 115 insertions(+), 18 deletions(-) diff --git a/firebase-ai/CHANGELOG.md b/firebase-ai/CHANGELOG.md index 3244c980674..df89618a83f 100644 --- a/firebase-ai/CHANGELOG.md +++ b/firebase-ai/CHANGELOG.md @@ -5,6 +5,8 @@ * [changed] Introduced the `Voice` class, which accepts a voice name, and deprecated the `Voices` class. * [changed] **Breaking Change**: Updated `SpeechConfig` to take in `Voice` class instead of `Voices` class. * **Action Required:** Update all references of `SpeechConfig` initialization to use `Voice` class. +* [feature] Added support for extra schema properties like `title`, `minItems`, `maxItems`, `minimum` + and `maximum`. As well as support for the `anyOf` schema. # 16.0.0 diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt index 9eaa4590aad..e44d620c8d4 100644 --- a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt @@ -34,7 +34,7 @@ public abstract class StringFormat private constructor(internal val value: Strin */ public class Schema internal constructor( - public val type: String, + public val type: String? = null, public val description: String? = null, public val format: String? = null, public val nullable: Boolean? = null, @@ -42,6 +42,12 @@ internal constructor( public val properties: Map? = null, public val required: List? = null, public val items: Schema? = null, + public val title: String? = null, + public val minItems: Int? = null, + public val maxItems: Int? = null, + public val minimum: Double? = null, + public val maximum: Double? = null, + public val anyOf: List? = null ) { public companion object { @@ -53,12 +59,12 @@ internal constructor( */ @JvmStatic @JvmOverloads - public fun boolean(description: String? = null, nullable: Boolean = false): Schema = - Schema( - description = description, - nullable = nullable, - type = "BOOLEAN", - ) + public fun boolean( + description: String? = null, + nullable: Boolean = false, + title: String? = null + ): Schema = + Schema(description = description, nullable = nullable, type = "BOOLEAN", title = title) /** * Returns a [Schema] for a 32-bit signed integer number. @@ -73,12 +79,21 @@ internal constructor( @JvmStatic @JvmName("numInt") @JvmOverloads - public fun integer(description: String? = null, nullable: Boolean = false): Schema = + public fun integer( + description: String? = null, + nullable: Boolean = false, + title: String? = null, + minimum: Double? = null, + maximum: Double? = null + ): Schema = Schema( description = description, format = "int32", nullable = nullable, type = "INTEGER", + title = title, + minimum = minimum, + maximum = maximum, ) /** @@ -90,11 +105,20 @@ internal constructor( @JvmStatic @JvmName("numLong") @JvmOverloads - public fun long(description: String? = null, nullable: Boolean = false): Schema = + public fun long( + description: String? = null, + nullable: Boolean = false, + title: String? = null, + minimum: Double? = null, + maximum: Double? = null + ): Schema = Schema( description = description, nullable = nullable, type = "INTEGER", + title = title, + minimum = minimum, + maximum = maximum, ) /** @@ -106,8 +130,21 @@ internal constructor( @JvmStatic @JvmName("numDouble") @JvmOverloads - public fun double(description: String? = null, nullable: Boolean = false): Schema = - Schema(description = description, nullable = nullable, type = "NUMBER") + public fun double( + description: String? = null, + nullable: Boolean = false, + title: String? = null, + minimum: Double? = null, + maximum: Double? = null + ): Schema = + Schema( + description = description, + nullable = nullable, + type = "NUMBER", + title = title, + minimum = minimum, + maximum = maximum, + ) /** * Returns a [Schema] for a single-precision floating-point number. @@ -123,8 +160,22 @@ internal constructor( @JvmStatic @JvmName("numFloat") @JvmOverloads - public fun float(description: String? = null, nullable: Boolean = false): Schema = - Schema(description = description, nullable = nullable, type = "NUMBER", format = "float") + public fun float( + description: String? = null, + nullable: Boolean = false, + title: String? = null, + minimum: Double? = null, + maximum: Double? = null + ): Schema = + Schema( + description = description, + nullable = nullable, + type = "NUMBER", + format = "float", + title = title, + minimum = minimum, + maximum = maximum, + ) /** * Returns a [Schema] for a string. @@ -139,13 +190,15 @@ internal constructor( public fun string( description: String? = null, nullable: Boolean = false, - format: StringFormat? = null + format: StringFormat? = null, + title: String? = null, ): Schema = Schema( description = description, format = format?.value, nullable = nullable, - type = "STRING" + type = "STRING", + title = title ) /** @@ -176,6 +229,7 @@ internal constructor( optionalProperties: List = emptyList(), description: String? = null, nullable: Boolean = false, + title: String? = null ): Schema { if (!properties.keys.containsAll(optionalProperties)) { throw IllegalArgumentException( @@ -188,6 +242,7 @@ internal constructor( properties = properties, required = properties.keys.minus(optionalProperties.toSet()).toList(), type = "OBJECT", + title = title ) } @@ -203,13 +258,19 @@ internal constructor( public fun array( items: Schema, description: String? = null, - nullable: Boolean = false + nullable: Boolean = false, + title: String? = null, + minItems: Int? = null, + maxItems: Int? = null ): Schema = Schema( description = description, nullable = nullable, items = items, type = "ARRAY", + title = title, + minItems = minItems, + maxItems = maxItems ) /** @@ -230,7 +291,8 @@ internal constructor( public fun enumeration( values: List, description: String? = null, - nullable: Boolean = false + nullable: Boolean = false, + title: String? = null, ): Schema = Schema( description = description, @@ -238,7 +300,28 @@ internal constructor( nullable = nullable, enum = values, type = "STRING", + title = title ) + + /** + * Returns a [Schema] representing a value that must conform to *any* (one of) the provided + * sub-schema. + * + * Example: A field that can hold either a simple userID or a more detailed user object. + * + * Schema.anyOf( listOf( Schema.integer(description = "User ID"), Schema.obj(mapOf( + * ``` + * "userID" to Schema.integer(description = "User ID"), + * "username" to Schema.string(description = "Username") + * ``` + * )) ) + * + * @param schemas The list of valid schemas which could be here + */ + @JvmStatic + public fun anyOf( + schemas: List, + ): Schema = Schema(anyOf = schemas) } internal fun toInternal(): Internal = @@ -251,10 +334,16 @@ internal constructor( properties?.mapValues { it.value.toInternal() }, required, items?.toInternal(), + title, + minItems, + maxItems, + minimum, + maximum, + anyOf?.map { it.toInternal() }, ) @Serializable internal data class Internal( - val type: String, + val type: String? = null, val description: String? = null, val format: String? = null, val nullable: Boolean? = false, @@ -262,5 +351,11 @@ internal constructor( val properties: Map? = null, val required: List? = null, val items: Internal? = null, + val title: String? = null, + val minItems: Int? = null, + val maxItems: Int? = null, + val minimum: Double? = null, + val maximum: Double? = null, + val anyOf: List? = null ) } From d181dedfecb86b452e73a9d035d6eb01c94f558a Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Thu, 5 Jun 2025 11:22:36 -0700 Subject: [PATCH 2/6] fix tests --- .../google/firebase/ai/SerializationTests.kt | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt b/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt index d00f75c2714..9a16f6b5b46 100644 --- a/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt +++ b/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt @@ -175,18 +175,15 @@ internal class SerializationTests { "type": { "type": "string" }, - "format": { + "description": { "type": "string" }, - "description": { + "format": { "type": "string" }, "nullable": { "type": "boolean" }, - "items": { - "${'$'}ref": "Schema" - }, "enum": { "type": "array", "items": { @@ -204,7 +201,31 @@ internal class SerializationTests { "items": { "type": "string" } - } + }, + "items": { + "${'$'}ref": "Schema" + }, + "title": { + "type": "string" + }, + "minItems": { + "type": "integer" + }, + "maxItems": { + "type": "integer" + }, + "minimum": { + "type": "number" + }, + "maximum": { + "type": "number" + }, + "anyOf": { + "type": "array", + "items": { + "${'$'}ref": "Schema" + } + } } } """ From 357b4a540e02bb2d78a2c4e65018b8f56ee48403 Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Mon, 9 Jun 2025 11:02:35 -0700 Subject: [PATCH 3/6] update api text file --- firebase-ai/api.txt | 56 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/firebase-ai/api.txt b/firebase-ai/api.txt index 5645b466110..7b327948098 100644 --- a/firebase-ai/api.txt +++ b/firebase-ai/api.txt @@ -765,84 +765,136 @@ package com.google.firebase.ai.type { } public final class Schema { + method public static com.google.firebase.ai.type.Schema anyOf(java.util.List schemas); method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items); method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null); method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null); + method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null, Integer? minItems = null); + method public static com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null, Integer? minItems = null, Integer? maxItems = null); method public static com.google.firebase.ai.type.Schema boolean(); method public static com.google.firebase.ai.type.Schema boolean(String? description = null); method public static com.google.firebase.ai.type.Schema boolean(String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema boolean(String? description = null, boolean nullable = false, String? title = null); method public static com.google.firebase.ai.type.Schema enumeration(java.util.List values); method public static com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null); method public static com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false, String? title = null); + method public java.util.List? getAnyOf(); method public String? getDescription(); method public java.util.List? getEnum(); method public String? getFormat(); method public com.google.firebase.ai.type.Schema? getItems(); + method public Integer? getMaxItems(); + method public Double? getMaximum(); + method public Integer? getMinItems(); + method public Double? getMinimum(); method public Boolean? getNullable(); method public java.util.Map? getProperties(); method public java.util.List? getRequired(); - method public String getType(); + method public String? getTitle(); + method public String? getType(); method public static com.google.firebase.ai.type.Schema numDouble(); method public static com.google.firebase.ai.type.Schema numDouble(String? description = null); method public static com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null); + method public static com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public static com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public static com.google.firebase.ai.type.Schema numFloat(); method public static com.google.firebase.ai.type.Schema numFloat(String? description = null); method public static com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null); + method public static com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public static com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public static com.google.firebase.ai.type.Schema numInt(); method public static com.google.firebase.ai.type.Schema numInt(String? description = null); method public static com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null); + method public static com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public static com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public static com.google.firebase.ai.type.Schema numLong(); method public static com.google.firebase.ai.type.Schema numLong(String? description = null); method public static com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null); + method public static com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public static com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public static com.google.firebase.ai.type.Schema obj(java.util.Map properties); method public static com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList()); method public static com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null); method public static com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false); + method public static com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false, String? title = null); method public static com.google.firebase.ai.type.Schema str(); method public static com.google.firebase.ai.type.Schema str(String? description = null); method public static com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false); method public static com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.ai.type.StringFormat? format = null); + method public static com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.ai.type.StringFormat? format = null, String? title = null); + property public final java.util.List? anyOf; property public final String? description; property public final java.util.List? enum; property public final String? format; property public final com.google.firebase.ai.type.Schema? items; + property public final Integer? maxItems; + property public final Double? maximum; + property public final Integer? minItems; + property public final Double? minimum; property public final Boolean? nullable; property public final java.util.Map? properties; property public final java.util.List? required; - property public final String type; + property public final String? title; + property public final String? type; field public static final com.google.firebase.ai.type.Schema.Companion Companion; } public static final class Schema.Companion { + method public com.google.firebase.ai.type.Schema anyOf(java.util.List schemas); method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items); method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null); method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null); + method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null, Integer? minItems = null); + method public com.google.firebase.ai.type.Schema array(com.google.firebase.ai.type.Schema items, String? description = null, boolean nullable = false, String? title = null, Integer? minItems = null, Integer? maxItems = null); method public com.google.firebase.ai.type.Schema boolean(); method public com.google.firebase.ai.type.Schema boolean(String? description = null); method public com.google.firebase.ai.type.Schema boolean(String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema boolean(String? description = null, boolean nullable = false, String? title = null); method public com.google.firebase.ai.type.Schema enumeration(java.util.List values); method public com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null); method public com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema enumeration(java.util.List values, String? description = null, boolean nullable = false, String? title = null); method public com.google.firebase.ai.type.Schema numDouble(); method public com.google.firebase.ai.type.Schema numDouble(String? description = null); method public com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null); + method public com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public com.google.firebase.ai.type.Schema numFloat(); method public com.google.firebase.ai.type.Schema numFloat(String? description = null); method public com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null); + method public com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public com.google.firebase.ai.type.Schema numFloat(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public com.google.firebase.ai.type.Schema numInt(); method public com.google.firebase.ai.type.Schema numInt(String? description = null); method public com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null); + method public com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public com.google.firebase.ai.type.Schema numInt(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public com.google.firebase.ai.type.Schema numLong(); method public com.google.firebase.ai.type.Schema numLong(String? description = null); method public com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null); + method public com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null); + method public com.google.firebase.ai.type.Schema numLong(String? description = null, boolean nullable = false, String? title = null, Double? minimum = null, Double? maximum = null); method public com.google.firebase.ai.type.Schema obj(java.util.Map properties); method public com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList()); method public com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null); method public com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false); + method public com.google.firebase.ai.type.Schema obj(java.util.Map properties, java.util.List optionalProperties = emptyList(), String? description = null, boolean nullable = false, String? title = null); method public com.google.firebase.ai.type.Schema str(); method public com.google.firebase.ai.type.Schema str(String? description = null); method public com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false); method public com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.ai.type.StringFormat? format = null); + method public com.google.firebase.ai.type.Schema str(String? description = null, boolean nullable = false, com.google.firebase.ai.type.StringFormat? format = null, String? title = null); } public final class SerializationException extends com.google.firebase.ai.type.FirebaseAIException { From e105a8cb1dc795fbcc825f88ddd819a9a7540347 Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Mon, 9 Jun 2025 11:39:54 -0700 Subject: [PATCH 4/6] make type non-nullable --- firebase-ai/api.txt | 4 +- .../com/google/firebase/ai/type/Schema.kt | 50 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/firebase-ai/api.txt b/firebase-ai/api.txt index 7b327948098..40aeb2b85d7 100644 --- a/firebase-ai/api.txt +++ b/firebase-ai/api.txt @@ -793,7 +793,7 @@ package com.google.firebase.ai.type { method public java.util.Map? getProperties(); method public java.util.List? getRequired(); method public String? getTitle(); - method public String? getType(); + method public String getType(); method public static com.google.firebase.ai.type.Schema numDouble(); method public static com.google.firebase.ai.type.Schema numDouble(String? description = null); method public static com.google.firebase.ai.type.Schema numDouble(String? description = null, boolean nullable = false); @@ -841,7 +841,7 @@ package com.google.firebase.ai.type { property public final java.util.Map? properties; property public final java.util.List? required; property public final String? title; - property public final String? type; + property public final String type; field public static final com.google.firebase.ai.type.Schema.Companion Companion; } diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt index e44d620c8d4..13016ce3083 100644 --- a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt @@ -34,7 +34,7 @@ public abstract class StringFormat private constructor(internal val value: Strin */ public class Schema internal constructor( - public val type: String? = null, + public val type: String, public val description: String? = null, public val format: String? = null, public val nullable: Boolean? = null, @@ -47,7 +47,7 @@ internal constructor( public val maxItems: Int? = null, public val minimum: Double? = null, public val maximum: Double? = null, - public val anyOf: List? = null + public val anyOf: List? = null, ) { public companion object { @@ -62,7 +62,7 @@ internal constructor( public fun boolean( description: String? = null, nullable: Boolean = false, - title: String? = null + title: String? = null, ): Schema = Schema(description = description, nullable = nullable, type = "BOOLEAN", title = title) @@ -84,7 +84,7 @@ internal constructor( nullable: Boolean = false, title: String? = null, minimum: Double? = null, - maximum: Double? = null + maximum: Double? = null, ): Schema = Schema( description = description, @@ -110,7 +110,7 @@ internal constructor( nullable: Boolean = false, title: String? = null, minimum: Double? = null, - maximum: Double? = null + maximum: Double? = null, ): Schema = Schema( description = description, @@ -135,7 +135,7 @@ internal constructor( nullable: Boolean = false, title: String? = null, minimum: Double? = null, - maximum: Double? = null + maximum: Double? = null, ): Schema = Schema( description = description, @@ -165,7 +165,7 @@ internal constructor( nullable: Boolean = false, title: String? = null, minimum: Double? = null, - maximum: Double? = null + maximum: Double? = null, ): Schema = Schema( description = description, @@ -198,7 +198,7 @@ internal constructor( format = format?.value, nullable = nullable, type = "STRING", - title = title + title = title, ) /** @@ -208,6 +208,7 @@ internal constructor( * `String` and values of type [Schema]. * * **Example:** A `city` could be represented with the following object `Schema`. + * * ``` * Schema.obj(mapOf( * "name" to Schema.string(), @@ -229,7 +230,7 @@ internal constructor( optionalProperties: List = emptyList(), description: String? = null, nullable: Boolean = false, - title: String? = null + title: String? = null, ): Schema { if (!properties.keys.containsAll(optionalProperties)) { throw IllegalArgumentException( @@ -242,7 +243,7 @@ internal constructor( properties = properties, required = properties.keys.minus(optionalProperties.toSet()).toList(), type = "OBJECT", - title = title + title = title, ) } @@ -261,7 +262,7 @@ internal constructor( nullable: Boolean = false, title: String? = null, minItems: Int? = null, - maxItems: Int? = null + maxItems: Int? = null, ): Schema = Schema( description = description, @@ -270,14 +271,13 @@ internal constructor( type = "ARRAY", title = title, minItems = minItems, - maxItems = maxItems + maxItems = maxItems, ) /** * Returns a [Schema] for an enumeration. * * For example, the cardinal directions can be represented as: - * * ``` * Schema.enumeration(listOf("north", "east", "south", "west"), "Cardinal directions") * ``` @@ -300,7 +300,7 @@ internal constructor( nullable = nullable, enum = values, type = "STRING", - title = title + title = title, ) /** @@ -310,23 +310,29 @@ internal constructor( * Example: A field that can hold either a simple userID or a more detailed user object. * * Schema.anyOf( listOf( Schema.integer(description = "User ID"), Schema.obj(mapOf( + * * ``` * "userID" to Schema.integer(description = "User ID"), * "username" to Schema.string(description = "Username") * ``` + * * )) ) * * @param schemas The list of valid schemas which could be here */ @JvmStatic - public fun anyOf( - schemas: List, - ): Schema = Schema(anyOf = schemas) + public fun anyOf(schemas: List): Schema = Schema(type = "anyOf", anyOf = schemas) } - internal fun toInternal(): Internal = - Internal( - type, + internal fun toInternal(): Internal { + val cleanedType = + if (type == "anyOf") { + null + } else { + type + } + return Internal( + cleanedType, description, format, nullable, @@ -341,6 +347,8 @@ internal constructor( maximum, anyOf?.map { it.toInternal() }, ) + } + @Serializable internal data class Internal( val type: String? = null, @@ -356,6 +364,6 @@ internal constructor( val maxItems: Int? = null, val minimum: Double? = null, val maximum: Double? = null, - val anyOf: List? = null + val anyOf: List? = null, ) } From df2f0678e56bbe56aeb4cba49d8b3b35c33ea707 Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Mon, 9 Jun 2025 11:42:35 -0700 Subject: [PATCH 5/6] make anyOf name more consistent --- .../src/main/kotlin/com/google/firebase/ai/type/Schema.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt index 13016ce3083..ca4466e75fe 100644 --- a/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt +++ b/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Schema.kt @@ -321,12 +321,12 @@ internal constructor( * @param schemas The list of valid schemas which could be here */ @JvmStatic - public fun anyOf(schemas: List): Schema = Schema(type = "anyOf", anyOf = schemas) + public fun anyOf(schemas: List): Schema = Schema(type = "ANYOF", anyOf = schemas) } internal fun toInternal(): Internal { val cleanedType = - if (type == "anyOf") { + if (type == "ANYOF") { null } else { type From f686d463fbc152b50358ae8361685c6f3eaa93f5 Mon Sep 17 00:00:00 2001 From: David Motsonashvili Date: Mon, 9 Jun 2025 15:01:27 -0700 Subject: [PATCH 6/6] update version bump --- firebase-ai/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-ai/gradle.properties b/firebase-ai/gradle.properties index e6719a371ef..b686fdcb9db 100644 --- a/firebase-ai/gradle.properties +++ b/firebase-ai/gradle.properties @@ -12,5 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -version=16.1.1 +version=16.2.0 latestReleasedVersion=16.1.0