diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/CommunicateTool.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/CommunicateTool.kt index a8268d4f2..94f56afbe 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/CommunicateTool.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/CommunicateTool.kt @@ -47,7 +47,7 @@ object CommunicateTool { ), ) { input -> val parsed = tools.jackson.databind.ObjectMapper().readTree(input) - val message = parsed.get("message")?.asText() + val message = parsed.get("message")?.asString() ?: return@of Tool.Result.error("Missing 'message' parameter") val process = AgentProcess.get() diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/ProgressTool.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/ProgressTool.kt index 15d2e6c7e..4d6cc8589 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/ProgressTool.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/ProgressTool.kt @@ -40,7 +40,7 @@ object ProgressTool { ), ) { input -> val parsed = tools.jackson.databind.ObjectMapper().readTree(input) - val status = parsed.get("status")?.asText() + val status = parsed.get("status")?.asString() ?: return@of Tool.Result.error("Missing 'status' parameter") val process = AgentProcess.get() diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/support/LlmOperationsCommon.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/support/LlmOperationsCommon.kt index e7619ded4..5dd8d7242 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/support/LlmOperationsCommon.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/support/LlmOperationsCommon.kt @@ -167,9 +167,9 @@ internal class MaybeReturnDeserializer private constructor( private fun deserializeFailure(failureNode: JsonNode): MaybeReturn = when { failureNode is NullNode -> MaybeReturn.failure(ERROR_FAILURE_NULL) - !failureNode.isTextual -> MaybeReturn.failure(ERROR_FAILURE_NOT_STRING) - failureNode.asText().isBlank() -> MaybeReturn.failure(ERROR_FAILURE_EMPTY) - else -> MaybeReturn.failure(failureNode.asText()) + !failureNode.isString -> MaybeReturn.failure(ERROR_FAILURE_NOT_STRING) + failureNode.asString().isBlank() -> MaybeReturn.failure(ERROR_FAILURE_EMPTY) + else -> MaybeReturn.failure(failureNode.asString()) } private fun deserializeSuccess(successNode: JsonNode, ctxt: DeserializationContext): MaybeReturn { diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/chat/ContentPartDeserializer.kt b/embabel-agent-api/src/main/kotlin/com/embabel/chat/ContentPartDeserializer.kt index 5e0a0ba65..cb335e0e9 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/chat/ContentPartDeserializer.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/chat/ContentPartDeserializer.kt @@ -35,11 +35,11 @@ class ContentPartDeserializer : ValueDeserializer() { override fun deserialize(parser: JsonParser, context: DeserializationContext): ContentPart { val node: JsonNode = context.readTree(parser) - node[TEXT_FIELD]?.asText()?.let { text -> + node[TEXT_FIELD]?.asString()?.let { text -> return TextPart(text) } - val mimeType = node[MIME_TYPE_FIELD]?.asText() + val mimeType = node[MIME_TYPE_FIELD]?.asString() ?: throw MismatchedInputException.from( parser, ContentPart::class.java, "Content part must contain '$TEXT_FIELD' or '$MIME_TYPE_FIELD'", @@ -53,7 +53,7 @@ class ContentPartDeserializer : ValueDeserializer() { return when (classifyMimeType(mimeType)) { MediaKind.IMAGE -> ImagePart(mimeType, data) - MediaKind.DOCUMENT -> DocumentPart(mimeType, data, node[FILENAME_FIELD]?.takeUnless { it.isNull }?.asText()) + MediaKind.DOCUMENT -> DocumentPart(mimeType, data, node[FILENAME_FIELD]?.takeUnless { it.isNull }?.asString()) null -> throw MismatchedInputException.from( parser, ContentPart::class.java, "Unsupported media MIME type: $mimeType", diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/DomainTypeInputSchemaTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/DomainTypeInputSchemaTest.kt index 8018028a7..94a189d72 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/DomainTypeInputSchemaTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/DomainTypeInputSchemaTest.kt @@ -385,7 +385,7 @@ class DomainTypeInputSchemaTest { val jsonSchema = schema.toJsonSchema() val parsed = objectMapper.readTree(jsonSchema) - assertEquals("object", parsed.get("type").asText()) + assertEquals("object", parsed.get("type").asString()) } @Test @@ -424,10 +424,10 @@ class DomainTypeInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val properties = parsed.get("properties") - assertEquals("string", properties.get("name").get("type").asText()) - assertEquals("integer", properties.get("count").get("type").asText()) - assertEquals("number", properties.get("price").get("type").asText()) - assertEquals("boolean", properties.get("active").get("type").asText()) + assertEquals("string", properties.get("name").get("type").asString()) + assertEquals("integer", properties.get("count").get("type").asString()) + assertEquals("number", properties.get("price").get("type").asString()) + assertEquals("boolean", properties.get("active").get("type").asString()) } @Test @@ -470,11 +470,11 @@ class DomainTypeInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val tagsProperty = parsed.get("properties").get("tags") - assertEquals("array", tagsProperty.get("type").asText()) + assertEquals("array", tagsProperty.get("type").asString()) val items = tagsProperty.get("items") assertNotNull(items, "Array schema must have 'items' property") - assertEquals("string", items.get("type").asText()) + assertEquals("string", items.get("type").asString()) } @Test @@ -503,7 +503,7 @@ class DomainTypeInputSchemaTest { val properties = parsed.get("properties") val addressProperty = properties.get("address") - assertEquals("object", addressProperty.get("type").asText()) + assertEquals("object", addressProperty.get("type").asString()) val nestedProperties = addressProperty.get("properties") assertNotNull(nestedProperties) @@ -660,7 +660,7 @@ class DomainTypeInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val itemsProperty = parsed.get("properties").get("items") - assertEquals("array", itemsProperty.get("type").asText()) + assertEquals("array", itemsProperty.get("type").asString()) val itemsSchema = itemsProperty.get("items") assertNotNull(itemsSchema) diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/TypeBasedInputSchemaTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/TypeBasedInputSchemaTest.kt index 6efb00004..9103e7861 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/TypeBasedInputSchemaTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/TypeBasedInputSchemaTest.kt @@ -207,7 +207,7 @@ class TypeBasedInputSchemaTest { val jsonSchema = schema.toJsonSchema() val parsed = objectMapper.readTree(jsonSchema) - assertEquals("object", parsed.get("type").asText()) + assertEquals("object", parsed.get("type").asString()) } @Test @@ -231,9 +231,9 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val properties = parsed.get("properties") - assertEquals("string", properties.get("stringField").get("type").asText()) - assertEquals("integer", properties.get("intField").get("type").asText()) - assertEquals("boolean", properties.get("booleanField").get("type").asText()) + assertEquals("string", properties.get("stringField").get("type").asString()) + assertEquals("integer", properties.get("intField").get("type").asString()) + assertEquals("boolean", properties.get("booleanField").get("type").asString()) } @Test @@ -265,10 +265,10 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val properties = parsed.get("properties") - assertEquals("integer", properties.get("intField").get("type").asText()) - assertEquals("integer", properties.get("longField").get("type").asText()) - assertEquals("number", properties.get("doubleField").get("type").asText()) - assertEquals("number", properties.get("floatField").get("type").asText()) + assertEquals("integer", properties.get("intField").get("type").asString()) + assertEquals("integer", properties.get("longField").get("type").asString()) + assertEquals("number", properties.get("doubleField").get("type").asString()) + assertEquals("number", properties.get("floatField").get("type").asString()) } @Test @@ -282,7 +282,7 @@ class TypeBasedInputSchemaTest { // List may be detected as object due to type erasure assertNotNull(properties.get("listField")) // Array types are correctly detected - assertEquals("array", properties.get("arrayField").get("type").asText()) + assertEquals("array", properties.get("arrayField").get("type").asString()) } @Test @@ -293,7 +293,7 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val properties = parsed.get("properties") - assertEquals("object", properties.get("nested").get("type").asText()) + assertEquals("object", properties.get("nested").get("type").asString()) } } @@ -310,7 +310,7 @@ class TypeBasedInputSchemaTest { assertNotNull(jsonSchema) val parsed = objectMapper.readTree(jsonSchema) - assertEquals("object", parsed.get("type").asText()) + assertEquals("object", parsed.get("type").asString()) } } @@ -329,12 +329,12 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val tagsProperty = parsed.get("properties").get("tags") - assertEquals("array", tagsProperty.get("type").asText()) + assertEquals("array", tagsProperty.get("type").asString()) // This is the key assertion - arrays MUST have items property val items = tagsProperty.get("items") assertNotNull(items, "Array schema must have 'items' property for OpenAI compatibility") - assertEquals("string", items.get("type").asText()) + assertEquals("string", items.get("type").asString()) } @Test @@ -345,11 +345,11 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val scoresProperty = parsed.get("properties").get("scores") - assertEquals("array", scoresProperty.get("type").asText()) + assertEquals("array", scoresProperty.get("type").asString()) val items = scoresProperty.get("items") assertNotNull(items, "Array schema must have 'items' property for OpenAI compatibility") - assertEquals("integer", items.get("type").asText()) + assertEquals("integer", items.get("type").asString()) } @Test @@ -360,12 +360,12 @@ class TypeBasedInputSchemaTest { val parsed = objectMapper.readTree(jsonSchema) val itemsProperty = parsed.get("properties").get("items") - assertEquals("array", itemsProperty.get("type").asText()) + assertEquals("array", itemsProperty.get("type").asString()) // Array items should have a nested object schema val items = itemsProperty.get("items") assertNotNull(items, "Array schema must have 'items' property for OpenAI compatibility") - assertEquals("object", items.get("type").asText()) + assertEquals("object", items.get("type").asString()) // The nested object should have its own properties defined val nestedProperties = items.get("properties") @@ -383,22 +383,22 @@ class TypeBasedInputSchemaTest { // Top-level properties val properties = parsed.get("properties") - assertEquals("string", properties.get("title").get("type").asText()) - assertEquals("integer", properties.get("count").get("type").asText()) + assertEquals("string", properties.get("title").get("type").asString()) + assertEquals("integer", properties.get("count").get("type").asString()) // Entries array val entriesProperty = properties.get("entries") - assertEquals("array", entriesProperty.get("type").asText()) + assertEquals("array", entriesProperty.get("type").asString()) val items = entriesProperty.get("items") assertNotNull(items, "Array schema must have 'items' property") - assertEquals("object", items.get("type").asText()) + assertEquals("object", items.get("type").asString()) // Nested properties in the array items val nestedProperties = items.get("properties") assertNotNull(nestedProperties) - assertEquals("string", nestedProperties.get("name").get("type").asText()) - assertEquals("integer", nestedProperties.get("value").get("type").asText()) + assertEquals("string", nestedProperties.get("name").get("type").asString()) + assertEquals("integer", nestedProperties.get("value").get("type").asString()) } } } diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/progressive/UnfoldingShortcutTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/progressive/UnfoldingShortcutTest.kt index 7076247ab..732d788ab 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/progressive/UnfoldingShortcutTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/tool/progressive/UnfoldingShortcutTest.kt @@ -209,7 +209,7 @@ class UnfoldingShortcutTest { ), ) { input -> val parsed = tools.jackson.module.kotlin.jacksonObjectMapper().readTree(input) - taskName = parsed.get("name")?.asText() + taskName = parsed.get("name")?.asString() Tool.Result.text("Task '$taskName' created") } val listTasks = Tool.of("list_tasks", "List tasks") { Tool.Result.text("No tasks") } diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/support/ToolLoopLlmOperationsTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/support/ToolLoopLlmOperationsTest.kt index 7494ab67d..ebb2c74c2 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/support/ToolLoopLlmOperationsTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/support/ToolLoopLlmOperationsTest.kt @@ -164,7 +164,7 @@ class ToolLoopLlmOperationsTest { MaybeReturn(success = successValue) } tree.has("failure") -> { - MaybeReturn(failure = tree.get("failure").asText()) + MaybeReturn(failure = tree.get("failure").asString()) } else -> null } diff --git a/embabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/converters/jsonSchemaSupport.kt b/embabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/converters/jsonSchemaSupport.kt index 762f97630..c78e70b01 100644 --- a/embabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/converters/jsonSchemaSupport.kt +++ b/embabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/converters/jsonSchemaSupport.kt @@ -60,7 +60,7 @@ fun parseJsonSchema(schema: String): JsonNode? = /** * Return the schema `type` value if present. */ -fun JsonNode.schemaType(): String? = get("type")?.asText() +fun JsonNode.schemaType(): String? = get("type")?.asString() /** * Return the `properties` node if present. @@ -77,7 +77,7 @@ fun JsonNode.propertiesNode(): JsonNode? = get("properties") fun JsonNode.requiredFieldNames(): Set = get("required") ?.takeIf { it.isArray } - ?.mapNotNull { if (it.isTextual) it.asText() else null } + ?.mapNotNull { if (it.isString) it.asString() else null } ?.toSet() .orEmpty() @@ -193,7 +193,7 @@ private fun normalizeArraySchema( } private fun resolveLocalSchemaRef(rootSchemaNode: JsonNode, schemaNode: ObjectNode): ObjectNode? { - val ref = schemaNode.get("\$ref")?.takeIf { it.isTextual }?.asText() ?: return null + val ref = schemaNode.get("\$ref")?.takeIf { it.isString }?.asString() ?: return null if (!ref.startsWith("#/")) { return null } diff --git a/embabel-agent-common/embabel-agent-ai/src/test/kotlin/com/embabel/common/ai/converters/JacksonOutputConverterTest.kt b/embabel-agent-common/embabel-agent-ai/src/test/kotlin/com/embabel/common/ai/converters/JacksonOutputConverterTest.kt index 1cacc321c..7323e5206 100644 --- a/embabel-agent-common/embabel-agent-ai/src/test/kotlin/com/embabel/common/ai/converters/JacksonOutputConverterTest.kt +++ b/embabel-agent-common/embabel-agent-ai/src/test/kotlin/com/embabel/common/ai/converters/JacksonOutputConverterTest.kt @@ -677,7 +677,7 @@ World""" private fun tools.jackson.databind.JsonNode.requiredFieldNamesOrRefResolved( rootSchema: tools.jackson.databind.JsonNode, ): Set { - val ref = get("\$ref")?.takeIf { it.isTextual }?.asText() + val ref = get("\$ref")?.takeIf { it.isString }?.asString() if (ref != null && ref.startsWith("#/")) { val resolved = ref .removePrefix("#/")