diff --git a/firebase-ai/CHANGELOG.md b/firebase-ai/CHANGELOG.md index 8124611e322..3174d1364b8 100644 --- a/firebase-ai/CHANGELOG.md +++ b/firebase-ai/CHANGELOG.md @@ -8,6 +8,8 @@ * [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. * [fixed] Fix incorrect model name in count token requests to the developer API backend +* [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 * [feature] Initial release of the Firebase AI SDK (`firebase-ai`). This SDK *replaces* the previous diff --git a/firebase-ai/api.txt b/firebase-ai/api.txt index 5645b466110..40aeb2b85d7 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? 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? 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 { 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 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..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 @@ -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, ) /** @@ -155,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(), @@ -176,6 +230,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 +243,7 @@ internal constructor( properties = properties, required = properties.keys.minus(optionalProperties.toSet()).toList(), type = "OBJECT", + title = title, ) } @@ -203,20 +259,25 @@ 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, ) /** * Returns a [Schema] for an enumeration. * * For example, the cardinal directions can be represented as: - * * ``` * Schema.enumeration(listOf("north", "east", "south", "west"), "Cardinal directions") * ``` @@ -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,12 +300,39 @@ 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(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, @@ -251,10 +340,18 @@ 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 +359,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, ) } 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" + } + } } } """