Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions src/main/java/com/google/genai/Transformers.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import com.google.genai.types.VoiceConfig;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -221,14 +223,58 @@ public static Content tContent(Object content) {

/** Transforms an object to a Schema for the API. */
public static Schema tSchema(Object origin) {
Schema schema = null;
if (origin == null) {
return null;
} else if (origin instanceof Schema) {
return (Schema) origin;
schema = (Schema) origin;
} else if (origin instanceof JsonNode) {
return JsonSerializable.fromJsonNode((JsonNode) origin, Schema.class);
schema = JsonSerializable.fromJsonNode((JsonNode) origin, Schema.class);
} else {
throw new IllegalArgumentException("Unsupported schema type: " + origin.getClass());
}
return populatePropertyOrdering(schema);
}

private static Schema populatePropertyOrdering(Schema schema) {
if (schema == null) {
return null;
}
throw new IllegalArgumentException("Unsupported schema type: " + origin.getClass());
Schema.Builder builder = schema.toBuilder();
boolean modified = false;

if (schema.properties().isPresent() && !schema.properties().get().isEmpty()) {
Map<String, Schema> updatedProperties = new LinkedHashMap<>();
boolean childModified = false;
for (Map.Entry<String, Schema> entry : schema.properties().get().entrySet()) {
Schema originalChild = entry.getValue();
Schema populatedChild = populatePropertyOrdering(originalChild);
if (populatedChild != originalChild) {
childModified = true;
}
updatedProperties.put(entry.getKey(), populatedChild);
}
if (childModified) {
builder.properties(updatedProperties);
modified = true;
}

if (!schema.propertyOrdering().isPresent() && schema.properties().get().size() > 1) {
builder.propertyOrdering(new ArrayList<>(schema.properties().get().keySet()));
modified = true;
}
}

if (schema.items().isPresent()) {
Schema originalItems = schema.items().get();
Schema populatedItems = populatePropertyOrdering(originalItems);
if (populatedItems != originalItems) {
builder.items(populatedItems);
modified = true;
}
}

return modified ? builder.build() : schema;
}

public static SpeechConfig tSpeechConfig(Object speechConfig) {
Expand Down
19 changes: 14 additions & 5 deletions src/main/java/com/google/genai/types/Schema.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import com.google.auto.value.AutoValue;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.genai.JsonSerializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import java.util.*;

/**
* Schema is used to define the format of input/output data.
Expand Down Expand Up @@ -698,7 +696,18 @@ public Builder type(String type) {
return type(new Type(type));
}

public abstract Schema build();
abstract Schema autoBuild();

abstract Optional<Map<String, Schema>> properties();

abstract Optional<List<String>> propertyOrdering();

public Schema build() {
if (!propertyOrdering().isPresent() && properties().isPresent() && properties().get().size() > 1) {
propertyOrdering(new ArrayList<>(properties().get().keySet()));
}
return autoBuild();
}
}

/** Deserializes a JSON string to a Schema object. */
Expand Down
38 changes: 38 additions & 0 deletions src/test/java/com/google/genai/TransformersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.genai.types.File;
import com.google.genai.types.FunctionDeclaration;
Expand Down Expand Up @@ -126,6 +127,43 @@ public void testTSchema_Required_success() {
assertEquals(schema, transformedSchema);
}

@Test
public void testTSchema_PropertyOrdering_autoPopulated() {
Schema schema =
Schema.builder()
.type("OBJECT")
.properties(
ImmutableMap.of(
"name", Schema.builder().type("STRING").build(),
"age", Schema.builder().type("INTEGER").build()))
.build();

Schema transformedSchema = Transformers.tSchema(schema);
assertTrue(transformedSchema.propertyOrdering().isPresent());
assertEquals(
ImmutableList.of("name", "age"),
transformedSchema.propertyOrdering().get());
}

@Test
public void testTSchema_PropertyOrdering_preservedIfExplicit() {
Schema schema =
Schema.builder()
.type("OBJECT")
.properties(
ImmutableMap.of(
"name", Schema.builder().type("STRING").build(),
"age", Schema.builder().type("INTEGER").build()))
.propertyOrdering("age", "name")
.build();

Schema transformedSchema = Transformers.tSchema(schema);
assertTrue(transformedSchema.propertyOrdering().isPresent());
assertEquals(
ImmutableList.of("age", "name"),
transformedSchema.propertyOrdering().get());
}

@Test
public void testTTool_noFunctions_success() {
Tool tool =
Expand Down
Loading