Philipp Heuer
03/07/2026, 9:25 PMfun streamingWithToolsStrategy() = strategy("streaming_loop") {
val executeMultipleTools by nodeExecuteMultipleTools(parallelTools = true)
val nodeStreaming by nodeLLMRequestStreamingAndSendResults()
val mapStringToRequests by node<String, List<Message.Request>> { input ->
listOf(Message.User(content = input, metaInfo = RequestMetaInfo.Empty))
}
val applyRequestToSession by node<List<Message.Request>, List<Message.Request>> { input ->
llm.writeSession {
appendPrompt {
input.forEach { message ->
when (message) {
is Message.User -> user(message.content)
is Message.Tool.Result -> tool { result(message) }
else -> {}
}
}
}
}
input
}
val mapToolCallsToRequests by node<List<ReceivedToolResult>, List<Message.Request>> { input ->
input.map { it.toMessage() }
}
edge(nodeStart forwardTo mapStringToRequests)
edge(mapStringToRequests forwardTo applyRequestToSession)
edge(applyRequestToSession forwardTo nodeStreaming)
edge(nodeStreaming forwardTo executeMultipleTools onMultipleToolCalls { true })
edge(executeMultipleTools forwardTo mapToolCallsToRequests)
edge(mapToolCallsToRequests forwardTo applyRequestToSession)
edge(nodeStreaming forwardTo nodeFinish onCondition { it.filterIsInstance<Message.Tool.Call>().isEmpty() })
}
and then grab the streamed content/text via handleEvents.onLLMStreamingFrameReceived - while this does work, is this the right approach / correct so far?Sergei Pestrikov
03/17/2026, 9:25 AM