-
Notifications
You must be signed in to change notification settings - Fork 322
Description
Description
When using executeStructured with a @Serializable data class that contains a @Contextual property (e.g. java.util.UUID), the JSON schema generator throws an IllegalArgumentException before any LLM request is made. The GenericJsonSchemaGenerator.process() method does not handle the CONTEXTUAL serial kind.
@Serializable
data class ExpectedResponse(
@Contextual
@property:LLMDescription("The ID of the one asking a question")
val id: UUID,
@property:LLMDescription("Your response")
val response: String
)
val promptExecutor = SingleLLMPromptExecutor(GoogleLLMClient(apiKey))
promptExecutor.executeStructured<ExpectedResponse>(
prompt = prompt("my-prompt") {
user("Hi, my id is: 2d81bd6d-b60a-41e3-a652-f01f4a9386ea. How can you help me?")
},
model = GoogleModels.Gemini2_5Flash
)
Stack trace
java.lang.IllegalArgumentException: Encountered unsupported type while generating JSON schema: CONTEXTUAL
at ai.koog.prompt.structure.json.generator.GenericJsonSchemaGenerator.process(GenericJsonSchemaGenerator.kt:66)
at ai.koog.prompt.structure.json.generator.GenericJsonSchemaGenerator.processObject(GenericJsonSchemaGenerator.kt:172)
at ai.koog.prompt.structure.json.generator.StandardJsonSchemaGenerator.processObject(StandardJsonSchemaGenerator.kt:155)
Expected behavior
The JSON schema generator should resolve @Contextual properties by looking up the actual serializer from the SerializersModule and generating the schema based on the resolved serializer's descriptor (e.g. for UUID with a string serializer, it should emit {"type": "string"}). Alternatively, if resolution is not feasible, the error message should clearly explain that @Contextual is unsupported and suggest using @Serializable(with = ...) as a workaround.
Workaround
Use an explicit serializer annotation instead of @Contextual:
@Serializable
data class ExpectedResponse(
@Serializable(with = UUIDSerializer::class)
@property:LLMDescription("The ID of the one asking a question")
val id: UUID,
@property:LLMDescription("Your response")
val response: String
)
Or represent the field as a String and parse it manually.
Related issues
- Should Tool annotation parsing use the kotlinx.serialization description instead of pure reflection? #363 — Similar problem in the Tool annotation parsing path (uses reflection instead of kotlinx.serialization descriptors)
Environment
Koog version: 0.6.2
Kotlin version: 2.3.0
Platform: JVM