in prompt/prompt-structure/src/commonMain/kotlin/ai/koog/prompt/structure/json/generator/StandardJsonSchemaGenerator.kt [38:100]
override fun generate(
json: Json,
name: String,
serializer: KSerializer<*>,
descriptionOverrides: Map<String, String>,
excludedProperties: Set<String>,
): LLMParams.Schema.JSON.Standard {
val descriptorKind = serializer.descriptor.kind
require(
descriptorKind is PolymorphicKind ||
descriptorKind in listOf(StructureKind.CLASS, StructureKind.OBJECT, StructureKind.MAP)
) {
"Only object-like types are supported for ${this::class.simpleName} generator, got $descriptorKind"
}
val context = GenerationContext(
json = json,
descriptor = serializer.descriptor,
processedTypeDefs = mutableMapOf(),
currentDefPath = listOf(),
descriptionOverrides = descriptionOverrides,
excludedProperties = excludedProperties,
currentDescription = null
)
// Initial generated schema, it's still missing a few things that are added below
val generatedSchema = process(context)
// Check that no types have identical serial names
val duplicatedSerialNames = context.processedTypeDefs.keys
.map { it.serialName }
.groupingBy { it }
.eachCount()
.filter { it.value > 1 }
require(duplicatedSerialNames.isEmpty()) {
"""
Found duplicated serial type names, but for a proper type definitions processing by ${this::class.simpleName} generator they should be unique.
Duplicates: $duplicatedSerialNames
""".trimIndent()
}
// Prepare a proper type definitions map with serial names as type names
val typeDefinitions = context.processedTypeDefs.mapKeys { (descriptor, _) -> descriptor.serialName }
// Post-process generated schema to create a full schema
val schema = buildJsonObject {
put(JsonSchemaConsts.Keys.ID, name)
// Add type definitions if any were generated
if (context.processedTypeDefs.isNotEmpty()) {
put(JsonSchemaConsts.Keys.DEFS, JsonObject(typeDefinitions))
}
generatedSchema.entries.forEach { (key, value) -> put(key, value) }
}
return LLMParams.Schema.JSON.Standard(
name = name,
schema = schema,
)
}