openai-kotlin icon indicating copy to clipboard operation
openai-kotlin copied to clipboard

submitStreamingToolOutput fails to send the body

Open miguel-uvicuo opened this issue 1 year ago • 0 comments

Description

submitStreamingToolOutput throws an exception even before sending the message to openai API

Reason why is that submitStreamingToolOutput is setting the body as a mapOf("tool_outputs" to output, "stream" to true))

https://github.com/aallam/openai-kotlin/blob/f70d2f99fcf2d12e8b2c78b5e3b3c45fafb50c05/openai-client/src/commonMain/kotlin/com.aallam.openai.client/internal/api/RunsApi.kt#L117-L126

Problem is that mapOf() returns a LinkedHashMap, a Java class, not a Kotlin class, so it isn not annotated with @Serializable, nor is it automatically registered in Kotlinx Serialization’s standard module.

Image

As a result, when you try to submit tool outputs using streaming, you get the following exception:

Serializer for subclass 'LinkedHashMap' is not found in the polymorphic scope of 'Map'. 
Check if class with serial name 'LinkedHashMap' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'LinkedHashMap' has to be '@Serializable', and the base class 'Map' has to be sealed and '@Serializable'

Full stack trace:

Original Stack Trace:
		at com.aallam.openai.client.internal.http.HttpTransport.handleException(HttpTransport.kt:76)
		at com.aallam.openai.client.internal.http.HttpTransport.performSse(HttpTransport.kt:58)
		at com.aallam.openai.client.internal.http.HttpTransport$performSse$1.invokeSuspend(HttpTransport.kt)
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
		at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:231)
		at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:187)
		at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:159)
		at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:466)
		at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:500)
		at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:489)
		at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:364)
		at kotlinx.coroutines.ResumeAwaitOnCompletion.invoke(JobSupport.kt:1409)
		at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1502)
		at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:322)
		at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:239)
		at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:917)
		at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:874)
		at kotlinx.coroutines.JobSupport.makeCompleting$kotlinx_coroutines_core(JobSupport.kt:817)
		at kotlinx.coroutines.CompletableDeferredImpl.completeExceptionally(CompletableDeferred.kt:89)
		at io.ktor.client.plugins.sse.BuildersKt$serverSentEventsSession$2.invokeSuspend(builders.kt:58)
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
		at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
		at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
		at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
		at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
		at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:702)
Caused by: io.ktor.client.plugins.sse.SSEClientException: Serializer for subclass 'LinkedHashMap' is not found in the polymorphic scope of 'Map'.
Check if class with serial name 'LinkedHashMap' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'LinkedHashMap' has to be '@Serializable', and the base class 'Map' has to be sealed and '@Serializable'.
	at io.ktor.client.plugins.sse.BuildersKt.mapToSSEException(builders.kt:251)
	at io.ktor.client.plugins.sse.BuildersKt.access$mapToSSEException(builders.kt:1)
	at io.ktor.client.plugins.sse.BuildersKt$serverSentEventsSession$2.invokeSuspend(builders.kt:58)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:702)
Caused by: kotlinx.serialization.SerializationException: Serializer for subclass 'LinkedHashMap' is not found in the polymorphic scope of 'Map'.
Check if class with serial name 'LinkedHashMap' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'LinkedHashMap' has to be '@Serializable', and the base class 'Map' has to be sealed and '@Serializable'.
	at kotlinx.serialization.internal.AbstractPolymorphicSerializerKt.throwSubtypeNotRegistered(AbstractPolymorphicSerializer.kt:102)
	at kotlinx.serialization.internal.AbstractPolymorphicSerializerKt.throwSubtypeNotRegistered(AbstractPolymorphicSerializer.kt:114)
	at kotlinx.serialization.PolymorphicSerializerKt.findPolymorphicSerializer(PolymorphicSerializer.kt:109)
	at kotlinx.serialization.json.internal.StreamingJsonEncoder.encodeSerializableValue(StreamingJsonEncoder.kt:242)
	at kotlinx.serialization.json.internal.JsonStreamsKt.encodeByWriter(JsonStreams.kt:31)
	at kotlinx.serialization.json.Json.encodeToString(Json.kt:81)
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serializeContent(KotlinxSerializationConverter.kt:91)
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serialize(KotlinxSerializationConverter.kt:55)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.ContentNegotiation$lambda$13$convertRequest(ContentNegotiation.kt:184)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.access$ContentNegotiation$lambda$13$convertRequest(ContentNegotiation.kt:1)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$1.invokeSuspend(ContentNegotiation.kt:242)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$1.invoke(ContentNegotiation.kt)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$1.invoke(ContentNegotiation.kt)
	at io.ktor.client.plugins.api.TransformRequestBodyHook$install$1.invokeSuspend(KtorCallContexts.kt:78)
	at io.ktor.client.plugins.api.TransformRequestBodyHook$install$1.invoke(KtorCallContexts.kt)
	at io.ktor.client.plugins.api.TransformRequestBodyHook$install$1.invoke(KtorCallContexts.kt)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.client.plugins.RequestError$install$1.invokeSuspend(HttpCallValidator.kt:134)
	at io.ktor.client.plugins.RequestError$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.client.plugins.RequestError$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.client.plugins.SetupRequestContext$install$1.invokeSuspend$proceed(HttpRequestLifecycle.kt:40)
	at io.ktor.client.plugins.SetupRequestContext$install$1.access$invokeSuspend$proceed(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.SetupRequestContext$install$1$1.invoke(HttpRequestLifecycle.kt:40)
	at io.ktor.client.plugins.SetupRequestContext$install$1$1.invoke(HttpRequestLifecycle.kt:40)
	at io.ktor.client.plugins.HttpRequestLifecycleKt$HttpRequestLifecycle$1$1.invokeSuspend(HttpRequestLifecycle.kt:27)
	at io.ktor.client.plugins.HttpRequestLifecycleKt$HttpRequestLifecycle$1$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.HttpRequestLifecycleKt$HttpRequestLifecycle$1$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.SetupRequestContext$install$1.invokeSuspend(HttpRequestLifecycle.kt:40)
	at io.ktor.client.plugins.SetupRequestContext$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.SetupRequestContext$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:86)
	at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:1329)
	at io.ktor.client.statement.HttpStatement.fetchStreamingResponse(HttpStatement.kt:102)
	at io.ktor.client.plugins.sse.BuildersKt$serverSentEventsSession$2.invokeSuspend(builders.kt:258)
	... 8 more

Steps to Reproduce

  1. Try to submit a streaming tool output using submitStreamingToolOutput

Environment

  • openai-kotlin version: 4.0.1
  • Kotlin version: 2.1.0
  • OS: macOs

miguel-uvicuo avatar Feb 12 '25 09:02 miguel-uvicuo