@@ -106,8 +106,17 @@ private fun MessageTimestamp(info: soy.iko.opencode.data.model.MessageInfo) {
109+// NumberFormat.getNumberInstance performs an expensive ICU locale lookup + object
110+// construction on every call. Reuse a thread-local instance so repeated calls (e.g.
111+// when the message list re-seeds after a reconnect and every visible assistant bubble
112+// recomposes at once) don't each pay that cost. Thread-local because NumberFormat is
114+private val tokenNumberFormat: ThreadLocal<java.text.NumberFormat> = ThreadLocal.withInitial {
115+ java.text.NumberFormat.getNumberInstance(java.util.Locale.US)
109private fun formatTokens(tokens: Tokens, format: String): String {
118private fun formatTokens(tokens: Tokens, format: String): String {
110− val nf = java.text.DecimalFormat.getNumberInstance(java.util.Locale.US)
119+ val nf = tokenNumberFormat.get()!!
111 return format.format(nf.format(tokens.input), nf.format(tokens.output))
120 return format.format(nf.format(tokens.input), nf.format(tokens.output))