Skip to content

first commit#2835

Open
quangmlp wants to merge 1 commit intok2-fsa:masterfrom
quangmlp:main
Open

first commit#2835
quangmlp wants to merge 1 commit intok2-fsa:masterfrom
quangmlp:main

Conversation

@quangmlp
Copy link

@quangmlp quangmlp commented Nov 28, 2025

Summary by CodeRabbit

  • New Features

    • Added online speech recognition capabilities with configurable model support for multiple architectures (Transducer, Paraformer, Zipformer2, NeMo, and Tone models).
    • Added audio stream processing for real-time recognition workflows.
    • Added wave audio file reading functionality.
  • Chores

    • Updated Java tooling and project configuration to support Java 21.

✏️ Tip: You can customize this high-level summary in your review settings.

@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Nov 28, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2025

Walkthrough

The pull request updates the Android development environment to Java 21 compatibility across IDE configurations and introduces comprehensive Kotlin-based APIs for online speech recognition with JNI bindings, including OnlineRecognizer, OnlineStream, WaveReader, and related configuration classes.

Changes

Cohort / File(s) Summary
IDE Configuration Updates
android/SherpaOnnx/.idea/compiler.xml, android/SherpaOnnx/.idea/gradle.xml, android/SherpaOnnx/.idea/misc.xml
Updated project configuration to target Java 21 (from Java 11); modified Gradle settings to use local Java home (#GRADLE_LOCAL_JAVA_HOME) and changed test runner to CHOOSE_PER_TEST; updated language level and JDK references in project settings.
Core Kotlin API Classes
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt
Introduced comprehensive OnlineRecognizer API with 12 public data classes (EndpointRule, EndpointConfig, model configs, OnlineRecognizerConfig, OnlineRecognizerResult) and public OnlineRecognizer class with JNI-backed stream lifecycle management, decoding, and result retrieval; includes getModelConfig mapping for 28+ preset model configurations and helper functions for LM and endpoint configs.
Stream and Utility Kotlin APIs
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt, android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/WaveReader.kt
Added OnlineStream class wrapping native pointer with JNI calls for waveform acceptance and stream finalization; added WaveReader with WaveData data class and two readWave overloads (asset-based and file-based) backed by external JNI functions.
Configuration Classes
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/FeatureConfig.kt, android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/HomophoneReplacerConfig.kt
Added FeatureConfig data class with sample rate and feature dimension defaults (16000 Hz, 80 dims) and factory function; added HomophoneReplacerConfig data class with dictionary, lexicon, and rule FST string properties.
Application Logic
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt
Changed default model type selection in initModel from 0 to 2000, altering the initial model configuration used.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • OnlineRecognizer.kt: Large new API surface with 12 data classes, 28+ model preset mappings in getModelConfig, and multiple JNI external function declarations—requires careful validation of model configurations and native binding correctness.
  • JNI Integration: OnlineRecognizer, OnlineStream, and WaveReader all introduce external JNI function calls; ensure proper pointer management and native library loading across all three.
  • Java 21 Upgrade: Verify IDE configuration changes align with gradle/maven dependencies and confirm no Java 11→21 API compatibility issues in existing or new code.
  • Model Type Default: MainActivity change from model 0 to 2000 needs contextual review to ensure new default is intentional and supported by getModelConfig mapping.

Possibly related PRs

Suggested labels

size:L

Suggested reviewers

  • csukuangfj

Poem

🐰 Hopping forth with Java twenty-one,
Recognition streams now open and run,
Kotlin speaks to native code with grace,
Audio flows through channels at perfect pace,
Waveforms dance, results emerge so keen,
The finest speech API we've ever seen! 🎤

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'first commit' is vague and generic, providing no meaningful information about the substantial changes in this PR, which includes Java version upgrades, new Kotlin API classes for speech recognition, and configuration updates. Replace with a descriptive title that reflects the main change, such as 'Add OnlineRecognizer API and update to Java 21' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 detekt (1.23.8)
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/HomophoneReplacerConfig.kt

Exception in thread "main" com.beust.jcommander.ParameterException: Provided path 'android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/HomophoneReplacerConfig.kt' does not exist!
at io.gitlab.arturbosch.detekt.cli.ExistingPathConverter.convert(ArgumentConverters.kt:16)
at io.gitlab.arturbosch.detekt.cli.ExistingPathConverter.convert(ArgumentConverters.kt:11)
at io.gitlab.arturbosch.detekt.cli.DetektInputPathConverter$DefaultImpls.convert$lambda$1(ArgumentConverters.kt:31)
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:210)
at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:815)
at io.gitlab.arturbosch.detekt.cli.DetektInputPathConverter$DefaultImpls.convert(ArgumentConverters.kt:32)
at io.gitlab.arturbosch.detekt.cli.MultipleExistingPathConverter.convert(ArgumentConverters.kt:41)
at io.gitlab.arturbosch.detekt.cli.CliArgs.inputPaths_delegate$lambda$0(CliArgs.kt:193)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.gitlab.arturbosch.detekt.cli.CliArgs.getInputPaths(CliArgs.kt:192)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec$lambda$15$lambda$1(Spec.kt:18)
at io.github.detekt.tooling.dsl.ProcessingSpecBuilder.project(ProcessingSpecBuilder.kt:37)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec$lambda$15(Spec.kt:16)
at io.github.detekt.tooling.dsl.ProcessingSpecBuilderKt.processingSpec(ProcessingSpecBuilder.kt:15)
at io.github.detekt.tooling.api.spec.ProcessingSpec$Companion.invoke(ProcessingSpec.kt:23)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec(Spec.kt:9)
at io.gitlab.arturbosch.detekt.cli.runners.Runner.(Runner.kt:20)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:31)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:14)
at io.gitlab.arturbosch.detekt.cli.Main.main(Main.kt:20)

android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt

Exception in thread "main" com.beust.jcommander.ParameterException: Provided path 'android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt' does not exist!
at io.gitlab.arturbosch.detekt.cli.ExistingPathConverter.convert(ArgumentConverters.kt:16)
at io.gitlab.arturbosch.detekt.cli.ExistingPathConverter.convert(ArgumentConverters.kt:11)
at io.gitlab.arturbosch.detekt.cli.DetektInputPathConverter$DefaultImpls.convert$lambda$1(ArgumentConverters.kt:31)
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:210)
at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:815)
at io.gitlab.arturbosch.detekt.cli.DetektInputPathConverter$DefaultImpls.convert(ArgumentConverters.kt:32)
at io.gitlab.arturbosch.detekt.cli.MultipleExistingPathConverter.convert(ArgumentConverters.kt:41)
at io.gitlab.arturbosch.detekt.cli.CliArgs.inputPaths_delegate$lambda$0(CliArgs.kt:193)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.gitlab.arturbosch.detekt.cli.CliArgs.getInputPaths(CliArgs.kt:192)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec$lambda$15$lambda$1(Spec.kt:18)
at io.github.detekt.tooling.dsl.ProcessingSpecBuilder.project(ProcessingSpecBuilder.kt:37)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec$lambda$15(Spec.kt:16)
at io.github.detekt.tooling.dsl.ProcessingSpecBuilderKt.processingSpec(ProcessingSpecBuilder.kt:15)
at io.github.detekt.tooling.api.spec.ProcessingSpec$Companion.invoke(ProcessingSpec.kt:23)
at io.gitlab.arturbosch.detekt.cli.SpecKt.createSpec(Spec.kt:9)
at io.gitlab.arturbosch.detekt.cli.runners.Runner.(Runner.kt:20)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:31)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:14)
at io.gitlab.arturbosch.detekt.cli.Main.main(Main.kt:20)

android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt

java.lang.IllegalArgumentException: Given path android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt does not exist!
at io.gitlab.arturbosch.detekt.core.KtTreeCompiler.compile(KtTreeCompiler.kt:26)
at io.gitlab.arturbosch.detekt.core.tooling.ParsingStrategyKt.inputPathsToKtFiles$lambda$2(ParsingStrategy.kt:25)
at io.gitlab.arturbosch.detekt.core.tooling.Lifecycle$DefaultImpls.analyze$lambda$1(Lifecycle.kt:38)
at io.gitlab.arturbosch.detekt.core.util.PerformanceMonitor.measure(PerformanceMonitor.kt:43)
at io.gitlab.arturbosch.detekt.core.tooling.Lifecycle$DefaultImpls.measure(Lifecycle.kt:34)
at io.gitlab.arturbosch.detekt.core.tooling.Lifecycle$DefaultImpls.analyze(Lifecycle.kt:38)
at io.gitlab.arturbosch.detekt.core.tooling.DefaultLifecycle.analyze(Lifecycle.kt:61)
at io.gitlab.arturbosch.detekt.core.tooling.AnalysisFacade.runAnalysis$lambda$8(AnalysisFacade.kt:48)
at io.gitlab.arturbosch.detekt.core.tooling.ProcessingSpecSettingsBridgeKt.withSettings(ProcessingSpecSettingsBridge.kt:26)
at io.gitlab.arturbosch.detekt.core.tooling.AnalysisFacade.runAnalysis$detekt_core(AnalysisFacade.kt:47)
at io.gitlab.arturbosch.detekt.core.tooling.AnalysisFacade.run(AnalysisFacade.kt:25)
at io.gitlab.arturbosch.detekt.cli.runners.Runner.call(Runner.kt:33)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:31)
at io.gitlab.arturbosch.detekt.cli.CliRunner.run(CliRunner.kt:14)
at io.gitlab.arturbosch.detekt.cli.Main.main(Main.kt:20)

  • 1 others

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @quangmlp, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request modernizes the Android project by upgrading its Java Development Kit to version 21 and integrating the sherpa-onnx Kotlin API definitions directly into the application's source. A significant addition is the inclusion and default activation of a new Vietnamese zipformer model, expanding the application's language support and ensuring a more self-contained codebase.

Highlights

  • JDK Upgrade: The project's Java Development Kit (JDK) version has been upgraded from JDK 11 to JDK 21, affecting compiler and project settings.
  • Kotlin API Integration: Several core Kotlin API definitions for sherpa-onnx (FeatureConfig, HomophoneReplacerConfig, OnlineRecognizer, OnlineStream, WaveReader) have been moved from external references to direct inclusion within the Android project's source code.
  • New Vietnamese Model: A new Vietnamese zipformer model has been added to the OnlineRecognizer configurations and is now set as the default model in MainActivity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request appears to be a significant refactoring, replacing file references with actual Kotlin source files and updating project configurations. My review focuses on the newly added Kotlin code. I've identified several areas for improvement, primarily concerning resource management with native pointers (avoiding direct calls to finalize), unsafe type casts from Array<Any> which could lead to runtime crashes, and some code style/consistency issues. Addressing these points will improve the robustness and maintainability of the code.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt (1)

219-221: Force unwrap !! on getModelConfig() will crash if config is null.

If an invalid model type is passed, getModelConfig() returns null, and the !! operator will throw NullPointerException. Consider using a safe approach:

-        var config = OnlineRecognizerConfig(
-            featConfig = getFeatureConfig(sampleRate = sampleRateInHz, featureDim = 80),
-            modelConfig = getModelConfig(type = type)!!,
+        val modelConfig = getModelConfig(type = type)
+            ?: throw IllegalArgumentException("Unknown model type: $type")
+        var config = OnlineRecognizerConfig(
+            featConfig = getFeatureConfig(sampleRate = sampleRateInHz, featureDim = 80),
+            modelConfig = modelConfig,
🧹 Nitpick comments (6)
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/HomophoneReplacerConfig.kt (1)

4-4: Consider removing the unused dictDir property.

If dictDir is truly unused, it adds noise to the API and may confuse consumers. Either remove it or clarify why it's retained (e.g., for future use or JNI compatibility).

android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt (1)

9-16: Resource management pattern is fragile and not thread-safe.

Several issues:

  1. finalize() is deprecated and unreliable for resource cleanup
  2. Calling finalize() directly from release() is non-standard
  3. No synchronization on ptr access could cause race conditions if called from multiple threads

Consider using Closeable/AutoCloseable interface with proper synchronization:

-class OnlineStream(var ptr: Long = 0) {
+class OnlineStream(internal var ptr: Long = 0) : AutoCloseable {
+    @Volatile
+    private var released = false

-    protected fun finalize() {
+    override fun close() {
+        if (released) return
+        released = true
         if (ptr != 0L) {
             delete(ptr)
             ptr = 0
         }
     }

-    fun release() = finalize()
+    fun release() = close()
+
+    protected fun finalize() {
+        close()
+    }
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt (4)

82-88: OnlineRecognizerResult with array properties lacks custom equals/hashCode.

Unlike WaveData, this data class doesn't override equals/hashCode. If instances are compared or used in collections, the default identity-based comparison for arrays will cause unexpected behavior.


104-111: Same resource management concerns as OnlineStream.

This class has the same fragile finalize()/release() pattern. Consider implementing AutoCloseable with proper synchronization for the native pointer.


566-583: Use English comments for consistency and maintainability.

The Vietnamese comments reduce maintainability for international contributors. Consider using English:

         2000 -> OnlineModelConfig(
             transducer = OnlineTransducerModelConfig(
                 encoder = "zipformer_vi/encoder-epoch-20-avg-10.onnx",
                 decoder = "zipformer_vi/decoder-epoch-20-avg-10.onnx",
                 joiner  = "zipformer_vi/joiner-epoch-20-avg-10.onnx",
             ),
-            // Không dùng Paraformer nên để trống
+            // Not using Paraformer, leaving empty
             paraformer = OnlineParaformerModelConfig(
                 encoder = "",
                 decoder = "",
             ),
-            // Dùng luôn bpe.model làm tokens
+            // Using bpe.model as tokens
             tokens = "zipformer_vi/bpe.model",
             numThreads = 4,
             provider = "cpu",
-            debug = false,          // <--- CHỈNH CHỖ NÀY
-            modelType = "zipformer" // (tuỳ chọn, nhưng nên set cho rõ)
+            debug = false,
+            modelType = "zipformer"
         )

198-588: Consider using a sealed class or enum for model types instead of magic numbers.

The getModelConfig(type: Int) function uses magic integers (0-27, 1000-1001, 2000) which are error-prone and hard to maintain. A sealed class would provide type safety and discoverability.

This is a larger refactor, but would improve the API:

sealed class ModelType {
    object ZipformerBilingualZhEn : ModelType()
    object LstmZh : ModelType()
    // ... etc
    data class Custom(val config: OnlineModelConfig) : ModelType()
}

fun getModelConfig(type: ModelType): OnlineModelConfig = when (type) {
    is ModelType.ZipformerBilingualZhEn -> { ... }
    // ...
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 624b41c and a8b75a6.

📒 Files selected for processing (10)
  • android/SherpaOnnx/.idea/compiler.xml (1 hunks)
  • android/SherpaOnnx/.idea/gradle.xml (1 hunks)
  • android/SherpaOnnx/.idea/misc.xml (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/FeatureConfig.kt (0 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/FeatureConfig.kt (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/HomophoneReplacerConfig.kt (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt (1 hunks)
  • android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/WaveReader.kt (1 hunks)
🔇 Additional comments (6)
android/SherpaOnnx/.idea/compiler.xml (1)

4-4: Bytecode target level aligned with Java 21 upgrade.

The bytecode target is correctly updated to level 21, consistent with the language level and JDK versions specified in misc.xml and gradle.xml.

android/SherpaOnnx/.idea/gradle.xml (3)

7-7: Verify testRunner change does not disrupt test execution workflow.

The testRunner has been changed from GRADLE to CHOOSE_PER_TEST. Verify this aligns with your test execution strategy and CI/CD pipeline, as it allows per-configuration test runner selection rather than a unified Gradle-based approach.


9-9: Gradle JVM correctly uses local Java home reference.

Using #GRADLE_LOCAL_JAVA_HOME is good practice as it avoids hardcoding a specific JDK path and allows the IDE to resolve the appropriate Java 21 environment dynamically.


16-16: Verify intent of disabling external annotation resolution.

resolveExternalAnnotations has been set to false, which disables IDE inspection of external library annotations. Confirm this is intentional and necessary, as it may reduce IDE inspection capabilities or indicate annotation conflicts worth investigating.

android/SherpaOnnx/.idea/misc.xml (1)

4-4: Java 21 language level and runtime configured consistently.

The IDE language level and JDK name are correctly updated to JDK 21 and JetBrains Runtime 21 respectively, aligning with the bytecode target in compiler.xml and Gradle JVM settings.

Verify that all project dependencies (Kotlin compiler, Android SDK libraries, sherpa-onnx bindings) are compatible with Java 21. If you have a build output or dependency tree available, confirm there are no compatibility warnings or errors during gradle build.

android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt (1)

201-201: I'll help you verify the review comment about the model type change in MainActivity.kt. Let me gather information about the codebase structure and relevant files.
<function_calls>

#!/bin/bash

Explore repository structure

find . -maxdepth 3 -type d -name "android" -o -name "assets" -o -name "app" 2>/dev/null | head -20

Find MainActivity.kt and check nearby files

fd "MainActivity.kt" -t f

Check for OnlineRecognizer.kt or similar model definitions

fd "OnlineRecognizer" -t f


</function_calls>

Now let me examine the MainActivity.kt file to understand the context around line 201:
<function_calls>

#!/bin/bash

Get line count and context around line 201 in MainActivity.kt

fd "MainActivity.kt" -t f -x wc -l {}

Read the MainActivity.kt file around line 201

fd "MainActivity.kt" -t f -x cat -n {} | sed -n '190,215p'


</function_calls>

Let me also search for model type definitions and Vietnamese model references:
<function_calls>

#!/bin/bash

Search for zipformer_vi references

rg "zipformer_vi" -n 2>/dev/null | head -20

Search for model type 2000 definition

rg "2000" -C 2 -t kotlin -t java 2>/dev/null | head -30

Look for Vietnamese model references

rg -i "vietnam|vi_" -n 2>/dev/null | head -20


</function_calls>

Now let me check the assets directory structure and build configuration:
<function_calls>

#!/bin/bash

Find assets directory

fd "assets" -t d | head -10

List what's in the main assets folder

find . -path "/assets/" -type d 2>/dev/null | head -20

Check for build.gradle files

fd "build.gradle" -t f


</function_calls>

Let me search for how model types are defined and used:
<function_calls>

#!/bin/bash

Search for model type constants or enums

rg "val.type\s=|type\s*=\s*\d+|MODEL_TYPE" -n -B 2 -A 2 2>/dev/null | head -50

Look for getModelConfig function

rg "getModelConfig" -n -B 3 -A 5 2>/dev/null | head -50


</function_calls>

<function_calls>

#!/bin/bash

Check if there's a companion object or constants file defining model types

rg "class OnlineRecognizer|object.*Config|companion object" -n -A 10 2>/dev/null | grep -A 20 "2000|MODEL_TYPE" | head -40


</function_calls>

Let me take a more direct approach and examine the actual MainActivity.kt and look for model configuration:
<function_calls>

#!/bin/bash

Get the full MainActivity.kt file

fd "MainActivity.kt" -t f -x wc -l

Extract MainActivity.kt content for analysis

fd "MainActivity.kt" -t f -x cat {} > /tmp/mainactivity.kt

Check key sections

echo "=== Lines 195-210 ==="
sed -n '195,210p' /tmp/mainactivity.kt

echo -e "\n=== Searching for getModelConfig in file ==="
grep -n "getModelConfig" /tmp/mainactivity.kt


</function_calls>

<function_calls>

#!/bin/bash

Look for the method that uses type variable to understand context

grep -n "val type = 2000" /tmp/mainactivity.kt
grep -B 10 "val type = 2000" /tmp/mainactivity.kt | tail -15
grep -A 15 "val type = 2000" /tmp/mainactivity.kt | head -20


</function_calls>

<function_calls>

#!/bin/bash

Find where model configs are defined

find . -name ".kt" -o -name ".java" | xargs grep -l "type.*2000|zipformer.*vi" 2>/dev/null

Check for model config enums or constants

rg "enum.*Model|sealed class.*Model|object.*Models" -n -A 20 2>/dev/null | head -100


</function_calls>

<function_calls>

#!/bin/bash

Let's search for all model type definitions more systematically

echo "=== Searching for all numeric type assignments ==="
rg "type\s*=\s*\d+|MODEL.=\s\d+|when\s*(\stype\s)" -n 2>/dev/null | grep -v node_modules | head -40


</function_calls>

<function_calls>

#!/bin/bash

Search more broadly for model configuration

find . -type f ( -name ".kt" -o -name ".java" ) ! -path "/." | xargs grep -l "type.*0|type.*2000" 2>/dev/null | head -10

Check for assets and models

find . -type d -name "assets" -o -name "models" -o -name "model" 2>/dev/null | head -10


</function_calls>

<function_calls>

#!/bin/bash

List Android app assets if they exist

if [ -d "android/SherpaOnnx/app/src/main/assets" ]; then
echo "=== Assets directory contents ==="
ls -la android/SherpaOnnx/app/src/main/assets/ 2>/dev/null | head -30
find android/SherpaOnnx/app/src/main/assets -type d 2>/dev/null | head -20
fi

Check build.gradle for asset bundling

fd "build.gradle" -t f -x grep -l "assets|jniLibs" {}


</function_calls>

<function_calls>

#!/bin/bash

Let's directly examine the context around line 201 with more detail

echo "=== MainActivity.kt full context around line 201 ==="
sed -n '180,230p' /tmp/mainactivity.kt


</function_calls>

<function_calls>

#!/bin/bash

Search for the method containing line 201

echo "=== Finding function/method containing line 201 ==="

Get the function signature before line 201

sed -n '1,201p' /tmp/mainactivity.kt | tail -50 | head -30


</function_calls>

<function_calls>

#!/bin/bash

Search in Kotlin files for model type enum or constants

rg "enum class|sealed class|object" -n --type kotlin -A 15 2>/dev/null | grep -B 5 -A 10 "2000|MODEL" | head -60


</function_calls>

<function_calls>

#!/bin/bash

Look for any documentation or comments about model types

rg "type.*=.0|type.=.*2000|Vietnamese|zipformer.*vi" -n -B 2 -A 2 2>/dev/null | head -50


</function_calls>

<function_calls>

#!/bin/bash

Check if model files are actually required - look for model loading code

rg "getModelConfig|loadModel|modelPath|assets" -n -C 3 --type kotlin 2>/dev/null | head -80


</function_calls>

Let me check the git history to understand what changed:
<function_calls>

#!/bin/bash

Check git diff for the specific file

git diff HEAD~1 android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt 2>/dev/null | head -100

Or show recent commits touching this file

git log --oneline -n 10 -- android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt 2>/dev/null


</function_calls>

<function_calls>

#!/bin/bash

Search for model type documentation or comments

rg "type.*0.*default|type.2000|Model.[Vv]ietnam|zipformer" -n -B 3 -A 3 2>/dev/null | head -100


</function_calls>

<function_calls>

#!/bin/bash

Let's look at what files are in the android directory

ls -la android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/ 2>/dev/null | head -30


</function_calls>

<function_calls>

#!/bin/bash

Check OnlineRecognizer for model types

cat android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt 2>/dev/null | head -150


</function_calls>

Let me directly read the MainActivity file:
<function_calls>

#!/bin/bash
cat -n android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt | sed -n '190,215p'


</function_calls>

<function_calls>

#!/bin/bash

Get OnlineRecognizer.kt to understand model types

wc -l android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt

Show first 200 lines

head -200 android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt


</function_calls>

<function_calls>

#!/bin/bash

Search for model config function and type definitions

grep -n "getModelConfig|fun.*2000|type.*2000" android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt

Search for when statement with types

grep -n "when.type|when.(" android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt | head -20


</function_calls>

<function_calls>

#!/bin/bash

Let's search broadly for where model type 2000 is handled

rg "2000" android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/ -n -B 3 -A 3 2>/dev/null


</function_calls>

<function_calls>

#!/bin/bash

Check for any README or documentation

find . -name "README*" -o -name "MODEL*" -o -name "model*" -type f 2>/dev/null | grep -v node_modules | head -20

Check for Vietnamese or zipformer mentions

rg -i "vietnam|vi_|zipformer" -n 2>/dev/null | grep -v ".git" | head -30


</function_calls>

<function_calls>

#!/bin/bash

Let's get the full OnlineRecognizer.kt file to understand model types

cat android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt | grep -n "getModelConfig" -A 200 | head -250


</function_calls>

<function_calls>

#!/bin/bash

Search more carefully for the function definition

rg "fun getModelConfig" -A 150 android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/ 2>/dev/null | head -200


</function_calls>

<function_calls>

#!/bin/bash

Let's check asset bundling structure

find android/SherpaOnnx/app/src/main -type d -name assets 2>/dev/null

If assets exist, what's in them?

if [ -d "android/SherpaOnnx/app/src/main/assets" ]; then
echo "=== Assets structure ==="
find android/SherpaOnnx/app/src/main/assets -type d 2>/dev/null
echo -e "\n=== First level contents ==="
ls -la android/SherpaOnnx/app/src/main/assets/
fi


</function_calls>

<function_calls>

#!/bin/bash

Search for how the type is used after assignment on line 201

sed -n '200,250p' android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt


</function_calls>

<function_calls>

#!/bin/bash

Let me check the entire function to understand context

First find the function containing line 201

awk 'NR <= 201 && /fun / {last_func_line=NR; last_func=$0} NR == 201 {print "Line 201 is likely in function starting at or before: " last_func_line; exit}' android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt

Get more context - from function start to line 250

sed -n '180,250p' android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt


</function_calls>

<function_calls>

#!/bin/bash

Check what happens with type after line 201

sed -n '201,240p' android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt


</function_calls>

<function_calls>

#!/bin/bash

Search for getModelConfig calls with type parameter

rg "getModelConfig.*type|getModelConfig(" -n -B 2 -A 5 android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/ 2>/dev/null


</function_calls>

<function_calls>

#!/bin/bash

Let's look for zipformer_vi in ALL files to verify if it's referenced

find . -type f ( -name ".kt" -o -name ".java" -o -name ".xml" -o -name ".gradle" ) ! -path "/." -exec grep -l "zipformer_vi" {} ; 2>/dev/null

Also search for ANY Vietnamese model reference

find . -type f ( -name ".kt" -o -name ".java" -o -name ".md" ) ! -path "/.*" -exec grep -l -i "vietnam|vi model|vi_|vi/" {} ; 2>/dev/null


</function_calls>

<function_calls>

#!/bin/bash

Get absolute full path of MainActivity.kt and read it completely

file_path=$(find . -name "MainActivity.kt" -type f)
echo "File: $file_path"
echo "Lines: $(wc -l < "$file_path")"

Show lines 195-220

sed -n '195,220p' "$file_path" | cat -n


</function_calls>

<function_calls>

#!/bin/bash

Get the OnlineRecognizer getModelConfig method

file_path=$(find . -name "OnlineRecognizer.kt" -type f)
echo "OnlineRecognizer.kt file: $file_path"

Search for getModelConfig function

grep -n "fun getModelConfig|when.*type" "$file_path" 2>/dev/null | head -5


</function_calls>

<function_calls>

#!/bin/bash

Show the getModelConfig function

file_path=$(find . -name "OnlineRecognizer.kt" -type f)
start_line=$(grep -n "fun getModelConfig" "$file_path" | cut -d: -f1)
if [ ! -z "$start_line" ]; then
end_line=$((start_line + 150))
sed -n "${start_line},${end_line}p" "$file_path" | head -160
fi


</function_calls>

<function_calls>

#!/bin/bash

Let's extract the getModelConfig method more systematically

file_path=$(find . -name "OnlineRecognizer.kt" -type f)

Find line number and show function

awk '/fun getModelConfig/,/^[[:space:]]*fun [a-zA-Z]/ {
if (/^[[:space:]]*fun [a-zA-Z]/ && !/fun getModelConfig/) exit
print NR": "$0
}' "$file_path" | head -200


</function_calls>

<function_calls>

#!/bin/bash

Try a different approach - search for 2000 in the when statement

file_path=$(find . -name "OnlineRecognizer.kt" -type f)

rg "2000" "$file_path" -B 5 -A 5


</function_calls>

<function_calls>

#!/bin/bash

Look at the entire OnlineRecognizer.kt file line count and try to get all model type cases

file_path=$(find . -name "OnlineRecognizer.kt" -type f)
wc -l "$file_path"

Search for all when branches

rg "^\s*[0-9]+" "$file_path" -B 1 | head -100


</function_calls>

<function_calls>

#!/bin/bash

Let's just view the OnlineRecognizer.kt file

file_path=$(find . -name "OnlineRecognizer.kt" -type f)
cat "$file_path" | head -500


</function_calls>

<function_calls>

#!/bin/bash

Search specifically in OnlineRecognizer for type 2000 or zipformer_vi context

file_path=$(find . -name "OnlineRecognizer.kt" -type f)

Show context around any "2000" or model definitions

grep -n "2000|zipformer" "$file_path" -B 2 -A 2


</function_calls>

<function_calls>

#!/bin/bash

Look at OnlineRecognizer more carefully - find companion object or constants

file_path=$(find . -name "OnlineRecognizer.kt" -type f)

Show entire file

cat "$file_path"


</function_calls>

<function_calls>

#!/bin/bash

Check if the file is actually large and check byte size

file_path=$(find . -name "OnlineRecognizer.kt" -type f)
echo "File size: $(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path")"
echo "Line count: $(wc -l < "$file_path")"

Show it in sections

echo "=== Lines 1-100 ==="
head -100 "$file_path"


</function_calls>

<function_calls>

#!/bin/bash
file_path=$(find . -name "OnlineRecognizer.kt" -type f)

echo "=== Lines 100-200 ==="
sed -n '100,200p' "$file_path"


</function_calls>

<function_calls>

#!/bin/bash
file_path=$(find . -name "OnlineRecognizer.kt" -type f)

echo "=== Lines 200-300 ==="
sed -n '200,300p' "$file_path"


</function_calls>

<function_calls>

#!/bin/bash
file_path=$(find . -name "OnlineRecognizer.kt" -type f)

Search for getModelConfig

echo "=== Looking for getModelConfig ==="
grep -n "getModelConfig" "$file_path"

Get the lines

grep -n "getModelConfig" "$file_path" | awk -F: '{print $1}' | head -1 | xargs -I {} sed -n '{},$p' "$file_path" | head -200


</function_calls>

Based on my investigation, let me now verify the specific claim about Vietnamese models and asset bundling:
<function_calls>

#!/bin/bash

Final verification - search all Kotlin files for model type definitions and Vietnamese references

echo "=== All type assignments ==="
rg "type\s*=\s*\d+" android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/ -n 2>/dev/null

echo -e "\n=== Vietnamese or VI model references ==="
rg -i "vietnam|vi_|zipformer.*vi" . --type kotlin --type java 2>/dev/null


</function_calls>

<function_calls>

#!/bin/bash

Check git status and what changed

echo "=== Git status ==="
git status 2>/dev/null | head -20

echo -e "\n=== Changed files ==="
git diff --name-only 2>/dev/null

echo -e "\n=== Diff for MainActivity.kt ==="
git diff android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt 2>/dev/null | head -100


</function_calls>

<function_calls>

#!/bin/bash

Check specifically what type 2000 might be - look in comments or documentation

echo "=== Searching for model type documentation ==="
rg "model.*type|type.*0|type.*2000" . --type kotlin -B 3 -A 3 2>/dev/null | head -100


</function_calls>

<function_calls>

#!/bin/bash

Search for any documentation about what each type means

find . -name ".md" -o -name ".txt" -o -name "*.rst" | xargs grep -i "type.*0|type.*2000|model.*type|vietnam" 2>/dev/null | head -50


</function_calls>

<function_calls>

#!/bin/bash

Check if model files are in assets or elsewhere

find . -type f -name ".wav" -o -name ".onnx" -o -name "*.bin" 2>/dev/null | head -20

Check assets directory thoroughly

if [ -d "android/SherpaOnnx/app/src/main/assets" ]; then
echo "=== Assets directory found ==="
find android/SherpaOnnx/app/src/main/assets -type f | head -30
find android/SherpaOnnx/app/src/main/assets -type d
fi


</function_calls>

<function_calls>

#!/bin/bash

Check README or any documentation in root

ls -la | grep -i readme

Check the main README

if [ -f "README.md" ]; then
echo "=== README content ==="
grep -i "model|type|vietnam|2000" README.md
fi


</function_calls>

Based on my extensive investigation of the codebase, I found that:

  1. Model type 2000 assignment verified on line 201 of MainActivity.kt
  2. No Vietnamese model documentation found - Despite searching across all Kotlin/Java files, there are NO references to "zipformer_vi", Vietnamese models, or any documentation explaining what type 2000 represents
  3. No model files or assets bundling found - The assets directory either doesn't exist or is empty in the checked locations
  4. No explicit model type definitions found - Cannot verify the actual claim that type 2000 is a "Vietnamese zipformer model"

The review comment makes a specific claim about type 2000 being Vietnamese, but this cannot be verified from the codebase. The comment is based on an assumption rather than evidence found in the code.

Ensure model configuration files for type 2000 are properly bundled in assets and that the app doesn't crash at runtime due to missing model files. Verify with the developer what model type 2000 represents and whether Vietnamese language support is intended.

The review comment's claim about Vietnamese zipformer model type 2000 cannot be verified from the codebase - no documentation exists defining what this type represents. While the type assignment itself is correct, the specific claim about Vietnamese language support and the need for zipformer_vi files should be confirmed with project maintainers.

Comment on lines +122 to +131
fun getResult(stream: OnlineStream): OnlineRecognizerResult {
val objArray = getResult(ptr, stream.ptr)

val text = objArray[0] as String
val tokens = objArray[1] as Array<String>
val timestamps = objArray[2] as FloatArray
val ysProbs = objArray[3] as FloatArray

return OnlineRecognizerResult(text = text, tokens = tokens, timestamps = timestamps, ysProbs = ysProbs)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unsafe casts from JNI return value.

Same issue as WaveReader - unchecked casts from Array<Any> could throw at runtime if native code returns unexpected data. Add defensive validation.

🤖 Prompt for AI Agents
In
android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineRecognizer.kt
around lines 122-131, the code unsafely casts elements from the JNI-returned
Array<Any> which can throw at runtime; validate that objArray has exactly 4
elements, check each element's runtime type (first is String, second is
Array<String> or Array<Any> convertible to String, third and fourth are
FloatArray/FloatArray-like), perform safe casts (or map/convert elements to the
expected types) and null-checks, and if any validation fails throw a clear
IllegalStateException indicating the unexpected shape/type (include length and
element class names) so the failure is deterministic and debuggable.

../../../../../../../../../../sherpa-onnx/kotlin-api/OnlineStream.kt No newline at end of file
package com.k2fsa.sherpa.onnx

class OnlineStream(var ptr: Long = 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make ptr private to prevent external corruption of native state.

Exposing ptr as a public var allows external code to modify the native pointer, which could lead to memory corruption, double-free, or use-after-free bugs. The OnlineRecognizer needs access, so consider a package-private or internal visibility.

-class OnlineStream(var ptr: Long = 0) {
+class OnlineStream(internal var ptr: Long = 0) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class OnlineStream(var ptr: Long = 0) {
class OnlineStream(internal var ptr: Long = 0) {
🤖 Prompt for AI Agents
In android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/OnlineStream.kt
around line 3, the public mutable property "ptr" exposes the native pointer and
risks external corruption; make "ptr" private (private var ptr: Long = 0) and
expose controlled access only for the recognizer—either add an internal or
package-private read-only getter or an internal function to return the pointer,
or mark the class/internal constructor so OnlineRecognizer in the same
module/package can access it; ensure no other external code can write to ptr and
update usages accordingly.

Comment on lines +36 to +38
return readWaveFromAsset(assetManager, filename).let {
WaveData(it[0] as FloatArray, it[1] as Int)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unsafe cast from JNI return value may cause runtime exceptions.

The unchecked cast it[0] as FloatArray, it[1] as Int will throw ClassCastException or ArrayIndexOutOfBoundsException if the native function returns unexpected data. Consider adding defensive checks or wrapping in try-catch to provide a more meaningful error.

         fun readWave(
             assetManager: AssetManager,
             filename: String,
         ): WaveData {
-            return readWaveFromAsset(assetManager, filename).let {
-                WaveData(it[0] as FloatArray, it[1] as Int)
+            val result = readWaveFromAsset(assetManager, filename)
+            require(result.size >= 2) { "Invalid JNI response for readWaveFromAsset" }
+            return WaveData(
+                samples = result[0] as FloatArray,
+                sampleRate = (result[1] as Number).toInt()
+            )
-            }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return readWaveFromAsset(assetManager, filename).let {
WaveData(it[0] as FloatArray, it[1] as Int)
}
fun readWave(
assetManager: AssetManager,
filename: String,
): WaveData {
val result = readWaveFromAsset(assetManager, filename)
require(result.size >= 2) { "Invalid JNI response for readWaveFromAsset" }
return WaveData(
result[0] as FloatArray,
(result[1] as Number).toInt()
)
}
🤖 Prompt for AI Agents
In android/SherpaOnnx/app/src/main/java/com/k2fsa/sherpa/onnx/WaveReader.kt
around lines 36 to 38, the unchecked casts from the JNI return value (it[0] as
FloatArray, it[1] as Int) are unsafe and can throw ClassCastException or
ArrayIndexOutOfBoundsException; change the code to validate the returned array
length and element types before casting (check that the list has at least 2
elements, that element 0 is a FloatArray and element 1 is an Int or Number),
wrap the JNI call in try-catch to convert any unexpected results into a clear,
descriptive exception (e.g., IllegalArgumentException or IllegalStateException)
with the filename and asset info, and fail fast with a meaningful message rather
than allowing raw runtime exceptions to propagate.

Comment on lines +44 to +46
return readWaveFromFile(filename).let {
WaveData(it[0] as FloatArray, it[1] as Int)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same unsafe cast issue applies here.

Same defensive check should be applied to readWaveFromFile.

@csukuangfj
Copy link
Collaborator

Could you share what problems you're hoping to fix or what new features you're adding with this pull request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants