Skip to content

feat(NanoDSLAgent): Add validation/retry mechanism and UI rendering integration#500

Merged
phodal merged 4 commits intomasterfrom
feat/nanodsl-validation-rendering
Dec 8, 2025
Merged

feat(NanoDSLAgent): Add validation/retry mechanism and UI rendering integration#500
phodal merged 4 commits intomasterfrom
feat/nanodsl-validation-rendering

Conversation

@phodal
Copy link
Owner

@phodal phodal commented Dec 7, 2025

Summary

Implements GitHub Issue #499: Enhance NanoDSLAgent with two critical features:

  1. Validation & Retry: Validate AI-generated code with NanoParser; retry if invalid
  2. UI Rendering: Render generated NanoDSL code through CodingAgentRenderer

Part 1: Validation & Retry Mechanism

New Files Created:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt - expect class
  • Platform-specific actual implementations for JVM, Android, JS, WASM, iOS

Features:

  • JVM platforms: Use xuiper-ui's NanoParser via reflection for full AST parsing
  • Non-JVM platforms: Basic syntax validation (component definition, indentation, brackets)
  • Retry logic: Up to 3 retry attempts with error feedback to LLM
  • Error feedback: Previous errors included in retry prompt for self-correction

Part 2: Rendering Integration

Interface Changes:

  • Added renderNanoDSL(source, irJson?, metadata) to CodingAgentRenderer
  • Added TimelineItem.NanoDSLItem with fields: source, irJson, componentName, generationAttempts, isValid, warnings
  • Added JsNanoDSLData and updated JS exports

Renderer Implementations:

Platform File Features
CLI CliRenderer.ts Syntax-highlighted code output
TUI TuiRenderer.ts Markdown code block
Server ServerRenderer.ts Formatted code with line numbers
Compose ComposeRenderer.kt NanoDSLTimelineItem component
IntelliJ JewelRenderer.kt IdeaNanoDSLBubble component
VSCode mpp-core.ts nanodsl message type

Testing

Build verification:

./gradlew :mpp-core:compileKotlinJvm  #
./gradlew :mpp-core:compileKotlinJs   #
./gradlew :mpp-ui:compileKotlinJvm    #
cd mpp-idea && ../gradlew compileKotlin #

Checklist

  • Create NanoDSLValidator expect/actual classes
  • JVM implementation with full parsing via xuiper-ui
  • Basic validation for JS/WASM/iOS/Android
  • Update NanoDSLAgent with retry logic
  • Add renderNanoDSL() to CodingAgentRenderer
  • Add NanoDSLItem to TimelineItem
  • Implement rendering in all platforms
  • Update JS exports

Closes #499

Summary by CodeRabbit

  • New Features

    • NanoDSL generation with built-in validation and retry (default up to 3 attempts) and structured error/warning reporting.
    • Cross-platform NanoDSL parsing/validation and runtime-only timeline items with optional live preview when IR is available.
    • Rendering support added across UI targets (IDE, Compose, CLI, JS/Server/TUI, VS Code) to display NanoDSL source, status, warnings, and attempt counts.
  • Improvements

    • Replaced progress indicators with a safer animated variant for more reliable UI feedback.

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

Changed the run task in IDE configuration to :mpp-idea:runIde.
Replaces Jewel's CircularProgressIndicator with a custom implementation using Swing Timer to prevent ClassLoader issues with IntelliJ's bundled Compose runtime.
…ntegration

Implements GitHub Issue #499

## Summary
- Add NanoDSL validation with retry mechanism (up to 3 attempts)
- Integrate NanoDSL rendering into CodingAgentRenderer

## Part 1: Validation & Retry Mechanism
- Create NanoDSLValidator expect/actual classes for cross-platform validation
- JVM implementation uses xuiper-ui's NanoParser via reflection when available
- Non-JVM platforms (JS, WASM, iOS, Android) use basic syntax validation
- NanoDSLAgent now validates generated code and retries with error feedback

## Part 2: Rendering Integration
- Add renderNanoDSL() to CodingAgentRenderer interface
- Add NanoDSLItem to TimelineItem sealed class
- Implement rendering in all platforms:
  - TypeScript: CliRenderer, TuiRenderer, ServerRenderer with syntax highlighting
  - Compose: ComposeRenderer with NanoDSLTimelineItem component
  - IntelliJ: JewelRenderer with IdeaNanoDSLBubble component
  - VSCode: VSCodeRenderer with nanodsl message type

## Files Changed
### mpp-core
- src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (new)
- src/*/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.*.kt (platform actuals)
- src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
- src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
- src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
- src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt

### mpp-ui
- src/commonMain/kotlin/.../compose/agent/ComposeRenderer.kt
- src/commonMain/kotlin/.../compose/agent/AgentMessageList.kt
- src/jsMain/typescript/agents/render/*.ts

### mpp-idea
- src/main/kotlin/.../renderer/JewelRenderer.kt
- src/main/kotlin/.../components/timeline/IdeaNanoDSLBubble.kt (new)
- src/main/kotlin/.../components/timeline/IdeaTimelineContent.kt
- src/main/kotlin/.../toolwindow/knowledge/IdeaKnowledgeContent.kt

### mpp-vscode
- src/bridge/mpp-core.ts

Closes #499
Copilot AI review requested due to automatic review settings December 7, 2025 16:18
@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a cross-platform NanoDSL validation and parsing API with platform-specific actuals, integrates a retry-enabled generation loop into NanoDSLAgent, and wires NanoDSL rendering across Compose, IntelliJ, TypeScript, CLI/TUI, and VS Code frontends with a new timeline item model and UI components.

Changes

Cohort / File(s) Summary
Core API & Models
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt, mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt, mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
Adds expect class NanoDSLValidator with validate/parse, new data types NanoDSLValidationResult, ValidationError, NanoDSLParseResult; extends CodingAgentRenderer with renderNanoDSL; adds TimelineItem.NanoDSLItem.
Agent Logic
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
Replaces single-pass generation with retry loop (configurable maxRetries), integrates NanoDSLValidator for per-attempt validation, builds retry prompts/metadata, and returns structured success/failure metadata.
JVM Validator (full parser/reflection)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
JVM actual that attempts to delegate to xuiper-ui via reflection (validate/toJson), converts external results, and falls back to local basic validation and minimal IR when needed.
Android / iOS / JS / WASM Validators (lightweight)
mpp-core/src/androidMain/kotlin/.../NanoDSLValidator.android.kt, mpp-core/src/iosMain/kotlin/.../NanoDSLValidator.ios.kt, mpp-core/src/jsMain/kotlin/.../NanoDSLValidator.js.kt, mpp-core/src/wasmJsMain/kotlin/.../NanoDSLValidator.wasmJs.kt
Platform-specific actuals implementing basic validation (component header, indentation, bracket balance) and source-only IR generation for non-JVM targets.
JS Renderer Exports & Adapter
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
Adds JsNanoDSLData, extends JsCodingAgentRenderer with renderNanoDSL(data), and maps Kotlin renderer calls to the JS renderer adapter.
Compose Renderer & UI
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt, mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt
Adds renderNanoDSL in ComposeRenderer, appends NanoDSLItem to timeline, introduces NanoDSLTimelineItem composable, and marks NanoDSL items as runtime-only (not persisted).
IntelliJ UI & Renderer
mpp-idea/src/main/kotlin/.../components/timeline/IdeaNanoDSLBubble.kt, mpp-idea/src/main/kotlin/.../components/timeline/IdeaTimelineContent.kt, mpp-idea/src/main/kotlin/.../renderer/JewelRenderer.kt
New IdeaNanoDSLBubble composable and integration into timeline content and JewelRenderer.renderNanoDSL to emit TimelineItem.NanoDSLItem.
IntelliJ Progress Indicator & Replacements
mpp-idea/src/main/kotlin/.../compose/IdeaComposeEffects.kt, mpp-idea/src/main/kotlin/.../editor/IdeaMcpConfigDialog.kt, mpp-idea/src/main/kotlin/.../toolwindow/**, mpp-idea/src/main/kotlin/.../renderer/MermaidDiagramView.kt
Adds IdeaCircularProgressIndicator (Swing Timer-based) and replaces CircularProgressIndicator usages across multiple UI components with the new indicator; integrates NanoDSL display in knowledge view.
TypeScript / CLI / Server / TUI Renderers
mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts, CliRenderer.ts, ServerRenderer.ts, TuiRenderer.ts
Adds renderNanoDSL signature to BaseRenderer (no-op), implements rendering with highlighting and structured output in CLI/Server/TUI renderers (note: duplicate ServerRenderer implementation appears).
VS Code Bridge
mpp-vscode/src/bridge/mpp-core.ts
Adds VSCodeRenderer.renderNanoDSL to post a 'nanodsl' message containing source, irJson, componentName, attempts, isValid, and warnings.
IDE Run Config
.idea/runConfigurations/RunIDEA.xml
Updated Run IDEA Gradle task from :runIde to :mpp-idea:runIde.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • Reflection usage and fallback logic in NanoDSLValidator.jvm.kt (xuiper-ui detection, method lookups, exception safety).
    • Correctness and termination of the retry loop in NanoDSLAgent.kt (prompt composition, metadata, retry conditions).
    • Consistency of metadata keys and parsing across renderers and bridges (componentName, attempts, isValid, warnings).
    • UI changes: ensure new Compose components and IDEA Swing-timer indicator behave correctly under IntelliJ ClassLoader constraints.
    • Duplicate renderNanoDSL implementation in ServerRenderer.ts (cleanup).

Possibly related PRs

Poem

🐰 I hopped through code with careful paws,

Validated DSLs and fixed the flaws.
Retries I knitted, timelines I stitched,
From JVM dreams to browsers switched—
A tiny rabbit, proud and bright, code freshly enriched.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.62% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: adding validation/retry mechanism and UI rendering integration to NanoDSLAgent, which aligns with the primary objectives.
Linked Issues check ✅ Passed The PR successfully implements all major coding requirements from #499: cross-platform NanoDSLValidator with expect/actual classes [#499], retry loop in NanoDSLAgent [#499], structured validation errors [#499], platform renderers (Compose, CLI, TUI, Server, IntelliJ, VSCode) [#499], and TimelineItem.NanoDSLItem model [#499].
Out of Scope Changes check ✅ Passed All changes align with #499 requirements: validator implementations, agent retry logic, renderer integration, UI components, and Gradle configuration update for IDE task execution are all within scope of the validation/rendering feature.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/nanodsl-validation-rendering

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

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: 3

🧹 Nitpick comments (18)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (1)

182-227: IdeaCircularProgressIndicator implementation is lifecycle-safe and matches the CL-avoidance goal

Using DisposableEffect(Unit) to manage a Swing Timer and driving a simple Canvas arc via rotation state is a reasonable, coroutine-free way to implement a spinner here. Defaulting the color to JewelTheme.globalColors.text.info keeps it within the design system, and the size/strokeWidth parameters give enough flexibility for the call sites you’ve added below. No functional issues from this block.

If you later see performance/log spam in large UIs, you could consider a slightly lower tick rate (e.g., 30–40 fps) or a smaller sweep angle, but it’s not required now.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (1)

28-31: MCP config dialog spinners correctly switched to IdeaCircularProgressIndicator

Each loading path now uses IdeaCircularProgressIndicator with appropriate sizing (16.dp in the tools list row, 14.dp in compact headers/buttons), and the visibility conditions are unchanged (isLoading, serverState?.isLoading, isReloading). This keeps the UX identical while aligning with the new, safer indicator implementation.

You could slightly simplify a few call sites by omitting explicit modifier = Modifier when you don’t chain any modifiers, but that’s purely cosmetic.

Also applies to: 639-647, 712-715, 858-871, 974-990

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/knowledge/IdeaKnowledgeContent.kt (1)

801-845: NanoDSL bubble works but ignores validation metadata that’s already available

The NanoDSL branch renders source and basic header correctly, but it drops isValid/warnings from TimelineItem.NanoDSLItem. Consider optionally surfacing validity (e.g., ✓/⚠) and warnings here to align with NanoDSLTimelineItem/IdeaNanoDSLBubble behavior and make NanoDSL issues visible in this view as well.

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt (1)

229-238: Clean NanoDSL wiring, but composable has unused preview state and mismatched KDoc

RenderMessageItem correctly forwards NanoDSL fields, but NanoDSLTimelineItem currently has:

  • An unused showPreview state and an irJson parameter that is never read.
  • A KDoc that promises an “optional preview toggle” which doesn’t exist yet.
  • A small micro-inefficiency from calling source.lines() again in the footer.

Either (a) implement the preview toggle using irJson/showPreview, or (b) drop the unused state, unused param, and adjust the KDoc until preview is actually wired. You can also reuse the existing lines list for the footer count to avoid recomputing.

Example minimal clean‑up:

-/**
- * NanoDSL Timeline Item - displays generated NanoDSL code with optional preview toggle
- */
+/**
+ * NanoDSL Timeline Item - displays generated NanoDSL code
+ */
 @Composable
 fun NanoDSLTimelineItem(
     source: String,
-    irJson: String?,
+    irJson: String?, // keep only if a preview will be added soon
@@
-    modifier: Modifier = Modifier
-) {
-    var showPreview by remember { mutableStateOf(false) }
-    
+    modifier: Modifier = Modifier
+) {
@@
-                    val lines = source.lines()
-                    val maxLineNumWidth = lines.size.toString().length
+                    val lines = source.lines()
+                    val maxLineNumWidth = lines.size.toString().length
@@
-            Text(
-                text = "${source.lines().size} lines of NanoDSL code",
+            Text(
+                text = "${lines.size} lines of NanoDSL code",
                 fontSize = 10.sp,
                 color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f)
             )

Also applies to: 380-501

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt (1)

539-566: IntelliJ NanoDSL timeline integration is consistent with the shared model

The override correctly maps source, irJson, componentName, attempts, isValid, and warnings into TimelineItem.NanoDSLItem, so Jewel‑based UIs will see NanoDSL entries like other platforms. If NanoDSL component names can include non‑\w characters (e.g. dashes), you might later want a slightly broader regex for extraction, but the current approach is fine as a first pass.

mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts (1)

16-18: TUI NanoDSL rendering is wired correctly and follows existing message patterns

The new renderNanoDSL correctly consumes JsNanoDSLData, surfaces name/attempts/validity/warnings, and wraps the source in a fenced nanodsl block. For very large NanoDSL outputs you might consider reusing truncateText (similar to other tool outputs) to avoid flooding the TUI, but the current behavior is acceptable.

Also applies to: 299-325

mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts (1)

647-683: Static analysis ReDoS warning is a false positive.

The keywords and components arrays on lines 649-655 are hardcoded string literals, not user-controlled input. The generated regex patterns like \b(VStack)\b are safe and linear-time.

For a minor performance optimization, you could pre-compile these regexes outside the method to avoid recreating them on each call, but this is optional given the typical usage frequency.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt (2)

30-30: Unused state variable showPreview.

The showPreview state is declared but never read or modified. If live preview toggle is planned for future implementation, consider adding a TODO comment. Otherwise, remove it to avoid confusion.

-    var showPreview by remember { mutableStateOf(false) }
-    
+    // TODO: Add live preview toggle when NanoRenderer integration is ready
+    // var showPreview by remember { mutableStateOf(false) }

149-157: Reuse already-calculated lines variable.

item.source.lines() is called again on line 152 when lines was already computed on line 123.

                 // Footer with line count
                 Spacer(modifier = Modifier.height(4.dp))
                 Text(
-                    text = "${item.source.lines().size} lines of NanoDSL code",
+                    text = "${lines.size} lines of NanoDSL code",
                     style = JewelTheme.defaultTextStyle.copy(
                         fontSize = 10.sp,
                         color = JewelTheme.globalColors.text.info.copy(alpha = 0.5f)
                     )
                 )
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (1)

214-228: Manual JSON escaping is acceptable but fragile.

The current implementation handles common escape sequences. For improved robustness, consider using kotlinx.serialization.json if it's available in the module, as it would handle all edge cases (Unicode escapes, control characters, etc.).

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (1)

151-165: Exception handling doesn't update lastErrors for retry prompt.

If an exception occurs on attempt 1 or 2, the loop continues but lastErrors remains from the previous validation (or empty on first attempt). The next retry prompt won't include meaningful error context.

Consider capturing the exception message as a pseudo-error for retry context:

             } catch (e: Exception) {
                 logger.error(e) { "NanoDSL generation failed on attempt $attempt" }
+                lastErrors = listOf(ValidationError("Generation error: ${e.message}", 0))
                 if (attempt == maxRetries) {
                     onProgress("❌ Generation failed: ${e.message}")
                     return ToolResult.AgentResult(
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt (1)

32-87: Inconsistent validation depth compared to JS implementation.

The WASM implementation lacks the indentation-multiple-of-4 warnings and known-component checks that the JS implementation includes. Since both target browser environments, consider aligning the validation logic for consistent behavior.

Compare with NanoDSLValidator.js.kt lines 50-95 which includes:

  • Indentation multiple-of-4 check (line 66-68)
  • Known components validation (lines 71-95)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (1)

32-87: Consider aligning validation depth with JS implementation.

The iOS implementation lacks indentation-multiple-of-4 warnings and known-component checks present in the JS implementation. While this works, users on different platforms may receive different warning levels for the same code.

This is optional since the core error detection (component def, tabs, brackets) is present.

mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt (1)

1-152: Consider extracting shared validation logic to commonMain.

The performBasicValidation and createSourceOnlyIR functions are nearly identical across iOS, JS, WASM, and JVM fallback implementations. Extracting common logic to a shared helper in commonMain would:

  • Reduce ~300 lines of duplicated code
  • Ensure consistent validation behavior across platforms
  • Simplify maintenance when adding new validation rules

Example structure:

// In commonMain
internal object NanoDSLValidationHelper {
    fun performBasicValidation(source: String, includeWarnings: Boolean = true): NanoDSLValidationResult
    fun createSourceOnlyIR(source: String): String
}
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt (4)

16-35: Reflection-based NanoDSL detection is sound; ensure keep rules for Android shrinkers.

The lazy detection of cc.unitmesh.xuiper.dsl.NanoDSL via reflection and the fullParserAvailable flag look correct and failure-safe. On Android release builds, though, R8/Proguard may rename or strip this class/methods, which would make Class.forName fail even when the dependency is present. Consider documenting or adding keep rules for cc.unitmesh.xuiper.dsl.NanoDSL#validate(String) and #toJson(String, boolean) so full parsing remains available in optimized builds.


81-104: Reflection-based result conversion duplicates JVM logic; consider a shared helper.

convertValidationResult is essentially the same as the JVM implementation, including the “assume valid if conversion fails” behavior. That’s fine functionally, but it’s a clear duplication across jvmMain and androidMain. If you expect this to evolve (e.g., additional fields on the xuiper result), consider extracting a common JVM helper (or at least a small shared utility) to avoid divergence between Android and pure JVM.


106-161: Basic validation is consistent with iOS but lags behind wasmJs checks.

This performBasicValidation mirrors the iOS version (component presence, tabs, balanced parens/braces), but the wasmJs implementation also warns on non‑4‑space indentation and unknown component names. For more consistent behavior across non‑xuiper platforms—including Android when the full parser is missing—you might want to:

  • Reuse the richer wasmJs rules (indentation multiple‑of‑4, known component warnings), or
  • Factor a shared performBasicValidation into common code used by Android, iOS, and wasmJs, with platform-specific extensions if needed.

Right now the discrepancy is harmless but could surprise users moving between targets.


163-176: Manual JSON construction works but is brittle; consider centralizing escaping.

createMinimalIR hand‑escapes backslashes, quotes, and control characters into a JSON string. That’s acceptable for a fallback path, but it’s easy to miss edge cases or changes over time. If you already have a lightweight JSON utility in common code, consider reusing it here (or centralizing a shared “escape NanoDSL source to JSON string” helper) to avoid subtle encoding bugs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b411789 and 4d14aae.

📒 Files selected for processing (27)
  • .idea/runConfigurations/RunIDEA.xml (1 hunks)
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt (1 hunks)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (1 hunks)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt (1 hunks)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (1 hunks)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (3 hunks)
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (1 hunks)
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt (3 hunks)
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt (1 hunks)
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (1 hunks)
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (3 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (5 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt (2 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt (4 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt (3 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/knowledge/IdeaKnowledgeContent.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt (2 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt (3 hunks)
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts (2 hunks)
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts (2 hunks)
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts (2 hunks)
  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts (2 hunks)
  • mpp-vscode/src/bridge/mpp-core.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

**/*.kt: Use expect/actual pattern for platform-specific code (for example: Platform implementations)
Use concrete classes (not interfaces) and Promise (not Flow) for @JsExport annotations
Avoid emoji and UTF-8 characters in WASM code
When modifying CodingAgentRenderer, update ALL implementations: DefaultCodingAgentRenderer, ComposeRenderer, JewelRenderer, ServerSideRenderer, and JsRendererAdapter in Kotlin
When modifying CodingAgentRenderer, update JVM CLI implementations: CodingCliRenderer and ConsoleRenderer
Use AutoDevColors or MaterialTheme.colorScheme for Compose styling

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/knowledge/IdeaKnowledgeContent.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
**/*.{kt,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never use hardcoded colors - always use design tokens from the design system

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/knowledge/IdeaKnowledgeContent.kt
  • mpp-vscode/src/bridge/mpp-core.ts
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt
  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

When modifying CodingAgentRenderer, update ALL TypeScript implementations: BaseRenderer.ts, CliRenderer.ts, ServerRenderer.ts, and TuiRenderer.ts

Files:

  • mpp-vscode/src/bridge/mpp-core.ts
  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
mpp-vscode/src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

When modifying CodingAgentRenderer, update VSCode implementations: mpp-vscode/src/bridge/mpp-core.ts and mpp-vscode/src/providers/chat-view.ts

Files:

  • mpp-vscode/src/bridge/mpp-core.ts
mpp-ui/src/jsMain/typescript/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use semanticInk/semanticChalk design tokens from mpp-ui/src/jsMain/typescript/design-system/ for CLI/TUI styling

Files:

  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : When modifying `CodingAgentRenderer`, update JVM CLI implementations: `CodingCliRenderer` and `ConsoleRenderer`
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Run `./gradlew :mpp-ui:generateI18n4kFiles` command when updating i18n resources

Applied to files:

  • .idea/runConfigurations/RunIDEA.xml
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to mpp-vscode/src/**/*.ts : When modifying `CodingAgentRenderer`, update VSCode implementations: `mpp-vscode/src/bridge/mpp-core.ts` and `mpp-vscode/src/providers/chat-view.ts`

Applied to files:

  • mpp-vscode/src/bridge/mpp-core.ts
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.ts : When modifying `CodingAgentRenderer`, update ALL TypeScript implementations: `BaseRenderer.ts`, `CliRenderer.ts`, `ServerRenderer.ts`, and `TuiRenderer.ts`

Applied to files:

  • mpp-vscode/src/bridge/mpp-core.ts
  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : When modifying `CodingAgentRenderer`, update ALL implementations: `DefaultCodingAgentRenderer`, `ComposeRenderer`, `JewelRenderer`, `ServerSideRenderer`, and `JsRendererAdapter` in Kotlin

Applied to files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : When modifying `CodingAgentRenderer`, update JVM CLI implementations: `CodingCliRenderer` and `ConsoleRenderer`

Applied to files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt
  • mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to mpp-ui/src/jsMain/typescript/**/*.ts : Use `semanticInk`/`semanticChalk` design tokens from `mpp-ui/src/jsMain/typescript/design-system/` for CLI/TUI styling

Applied to files:

  • mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts
  • mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : Use concrete classes (not interfaces) and `Promise` (not `Flow`) for JsExport annotations

Applied to files:

  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : Use `AutoDevColors` or `MaterialTheme.colorScheme` for Compose styling

Applied to files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt
🧬 Code graph analysis (13)
mpp-vscode/src/bridge/mpp-core.ts (3)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (1)
  • source (201-221)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt (1)
  • source (90-98)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • irJson (24-37)
  • irJson (28-28)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (1)
  • IdeaCircularProgressIndicator (191-227)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (1)
  • IdeaCircularProgressIndicator (191-227)
mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts (3)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • isValid (6-10)
  • message (15-19)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (3)
  • message (83-108)
  • message (135-139)
  • source (201-221)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt (1)
  • source (90-98)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (1)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • validate (55-75)
  • validate (62-62)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (1)
  • IdeaCircularProgressIndicator (191-227)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt (4)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (3)
  • performBasicValidation (32-87)
  • validate (9-102)
  • validate (11-20)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (2)
  • performBasicValidation (111-209)
  • validate (36-56)
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt (3)
  • performBasicValidation (32-87)
  • validate (9-102)
  • validate (11-20)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • validate (55-75)
  • validate (62-62)
mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts (1)
mpp-ui/src/jsMain/typescript/design-system/theme-helpers.ts (2)
  • semanticChalk (15-42)
  • dividers (125-130)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (3)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanStep.kt (1)
  • generateId (116-118)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/AgentPlan.kt (1)
  • generateId (135-137)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanTask.kt (1)
  • generateId (151-153)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt (1)
  • IdeaCircularProgressIndicator (191-227)
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt (4)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (3)
  • convertValidationResult (83-106)
  • performBasicValidation (111-209)
  • validate (36-56)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (3)
  • performBasicValidation (32-87)
  • validate (9-102)
  • validate (11-20)
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt (3)
  • performBasicValidation (32-87)
  • validate (9-102)
  • validate (11-20)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • validate (55-75)
  • validate (62-62)
mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts (2)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (1)
  • source (201-221)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt (1)
  • source (90-98)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (1)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (2)
  • validate (55-75)
  • validate (62-62)
🪛 ast-grep (0.40.0)
mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts

[warning] 663-663: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\b(${keyword})\\b, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 669-669: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\b(${comp})\\b, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test mpp-core (KMP)
  • GitHub Check: Build
🔇 Additional comments (30)
.idea/runConfigurations/RunIDEA.xml (1)

13-13: The :mpp-idea:runIde Gradle task is properly defined in mpp-idea/build.gradle.kts. The change correctly references the new module's run configuration without issues.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt (1)

11-12: Mermaid loading overlay correctly migrated to IdeaCircularProgressIndicator

The swap to IdeaCircularProgressIndicator() in LoadingOverlay preserves the centered spinner UX while using the new, coroutine-free indicator. Import wiring is correct and no other behavior changes are introduced.

Also applies to: 95-101

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaAnalysisComponents.kt (1)

28-29: Progress indicators in analysis header and fix section are wired correctly

Replacing the old progress indicator with IdeaCircularProgressIndicator() in the header status pill and the Fix Generation section keeps the same visibility conditions (only while active/generating) and fits visually in the existing layouts. All usages rely on sensible defaults, and there’s no change to control flow.

Also applies to: 79-96, 190-207

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCommitComponents.kt (1)

19-20: Commit loading states migrated cleanly to IdeaCircularProgressIndicator

Both the full-panel loading state and the inline IdeaIssueIndicator now use IdeaCircularProgressIndicator, with a larger size = 20.dp for the inline chip where needed. The behavior and conditions mirror the old implementation, so this is a safe drop-in replacement.

Also applies to: 54-57, 275-278

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt (1)

89-91: NanoDSL timeline dispatch looks correct

Delegating TimelineItem.NanoDSLItem to IdeaNanoDSLBubble(item, project) cleanly integrates NanoDSL into the existing timeline dispatcher without affecting other cases.

mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts (1)

15-15: BaseRenderer NanoDSL hook is a safe, backwards‑compatible extension

Importing JsNanoDSLData and adding a non‑abstract renderNanoDSL(data: JsNanoDSLData) with a no‑op body cleanly extends the JS renderer API so derived renderers can opt into NanoDSL without impacting existing implementations.

Also applies to: 149-157

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt (1)

132-149: New renderNanoDSL hook is well‑shaped; verify all renderer implementations are updated

The renderNanoDSL(source, irJson, metadata) addition matches the NanoDSL use case and is safely backwards‑compatible thanks to the default no‑op implementation. Please double‑check that all expected renderers now either override this or intentionally rely on the default, including:

  • Kotlin: DefaultCodingAgentRenderer, ComposeRenderer, JewelRenderer, ServerSideRenderer, JsRendererAdapter, CodingCliRenderer, ConsoleRenderer
  • JS/TS: BaseRenderer and its concrete implementations (CliRenderer, ServerRenderer, TuiRenderer)
  • VSCode bridge/renderer (VSCodeRenderer and its Kotlin adapter object)

This keeps the behavior consistent with the AGENTS.md guidelines about updating all renderer implementations when CodingAgentRenderer changes. Based on learnings, this cross‑renderer alignment is required.

mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts (2)

505-542: LGTM! Clean implementation of renderNanoDSL for server-side rendering.

The method correctly uses semanticChalk design tokens as per coding guidelines, and the structure (header, validity indicator, warnings, line-numbered code, footer) aligns well with other renderer implementations.


11-12: Imports are correct.

The JsNanoDSLData type alias import follows the same pattern used in CliRenderer.ts.

mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts (2)

599-642: Well-implemented renderNanoDSL with syntax highlighting.

The method properly uses dividers.solid() and semanticChalk tokens from the design system, and provides helpful syntax highlighting for NanoDSL code.


16-16: Import correctly added.

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt (1)

193-221: Well-designed NanoDSLItem data class.

The implementation follows the established pattern of other TimelineItem subclasses with:

  • Comprehensive documentation explaining JVM vs non-JVM platform behavior
  • Sensible default values (generationAttempts = 1, isValid = true)
  • Useful hasLivePreview() helper for UI conditional rendering
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt (1)

24-161: Good use of design tokens.

The component correctly uses AutoDevColors and JewelTheme throughout, adhering to the coding guidelines that prohibit hardcoded colors.

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt (1)

1-76: Well-designed cross-platform validation API.

The abstractions are clean and well-documented:

  • NanoDSLParseResult sealed class with Success/Failure variants and convenient helper methods
  • ValidationError includes optional suggestion field for actionable error messages
  • Clear documentation of platform-specific behavior (JVM full parsing vs non-JVM lightweight checks)
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt (2)

562-589: Good implementation of renderNanoDSL for Compose.

The method correctly extracts metadata and creates a NanoDSLItem for the timeline. The fallback regex for component name extraction is a nice touch.

One consideration: the warnings are split by ; (line 577). If this is a convention, it should be documented somewhere (e.g., in the metadata handling code or NanoDSLAgent).


884-888: Appropriate decision to not persist NanoDSLItem.

The reasoning that NanoDSL items are runtime-only and can be regenerated is sound. This is consistent with the treatment of LiveTerminalItem.

mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt (2)

111-209: Solid basic validation implementation.

The validation covers essential checks:

  • Component definition presence
  • Indentation consistency (4-space rule)
  • Tab detection
  • Known component warnings
  • Bracket balance

The bracket counting could be enhanced to report the approximate location of imbalance, but the current implementation is acceptable for basic validation.


21-34: Well-implemented optional dependency loading.

The reflection-based approach for optional xuiper-ui integration is clean:

  • Proper exception handling
  • Good logging for debugging
  • Graceful fallback to basic validation
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (3)

38-46: LGTM! Well-structured constructor with validation support.

The new maxRetries parameter with a sensible default and the validator instance are properly initialized. The default of 3 retries aligns with the RunConfig(maxTurns = 3) in the companion object.


215-235: LGTM! Clean metadata construction.

The buildMap idiom with conditional put for optional fields is idiomatic Kotlin. All relevant metadata is captured including attempts, validity, and warnings.


183-210: LGTM! Clear retry prompt structure.

The retry prompt effectively combines the original request with structured error feedback, enabling the LLM to self-correct based on specific validation failures.

mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt (1)

89-101: LGTM! IR creation is consistent with other platforms.

The JSON escaping and structure match the iOS and JS implementations, ensuring cross-platform consistency for downstream consumers.

mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt (3)

87-98: LGTM! Well-designed JS-friendly data class.

JsNanoDSLData correctly uses Array<String> instead of List for JS interoperability and follows the pattern of other JS data classes in this file.


203-213: LGTM! Clean adapter implementation.

The metadata parsing correctly handles optional values with sensible defaults. The warnings splitting aligns with how they're joined in NanoDSLAgent.buildMetadata.


129-131: The renderNanoDSL method is properly defined in the CodingAgentRenderer interface with a default no-op implementation, so all implementations automatically inherit it without requiring explicit overrides. Implementations that need NanoDSL support (Compose, Jewel, JavaScript renderers) override it; those that don't (CLI, Console, Server renderers) correctly rely on the default. The design is complete and requires no changes.

mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt (1)

9-30: LGTM! Standard validation flow for iOS platform.

The validate/parse pattern correctly follows the expect/actual contract, with appropriate fallback to source-only IR since full AST parsing isn't available on iOS.

mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt (2)

35-132: LGTM! Comprehensive validation for JS platform.

This implementation provides the most thorough non-JVM validation including:

  • Component definition check
  • Indentation consistency (tabs forbidden, multiple-of-4 warnings)
  • Known components validation
  • Bracket balance verification

The logic aligns well with the JVM basic validation fallback.


137-151: LGTM! Consistent IR generation.

The createSourceOnlyIR method properly escapes all control characters and produces valid JSON structure matching other platform implementations.

mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt (2)

37-57: Validation flow and empty‑source handling look correct and robust.

The early check for source.isBlank() returning an explicit ValidationError("Empty source code", 0) and the subsequent preference for the full parser with a clean fallback to performBasicValidation give a clear, predictable contract for callers, including when the xuiper parser is present but fails. No issues here.


59-79: Parse behavior aligns with design and uses a sensible minimal‑IR fallback.

parse correctly:

  • Reuses validate and short‑circuits to Failure when invalid.
  • Delegates to the full parser when available, surfacing parser exceptions as Failure with a useful error message.
  • Falls back to createMinimalIR(source) only when the full parser is unavailable, which keeps JVM‑like strictness when xuiper is present while still enabling non‑xuiper Android builds to render something.

This matches the expected cross‑platform contract for Android’s hybrid JVM/non‑JVM role.

Comment on lines +102 to +105
} catch (e: Exception) {
logger.warn(e) { "Failed to convert validation result" }
NanoDSLValidationResult(isValid = true) // Assume valid if conversion fails
}
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

Reconsider fallback behavior when conversion fails.

Returning isValid = true when the conversion from xuiper-ui's result fails (line 104) could mask validation errors. Consider returning isValid = false with a warning, or propagating the conversion failure.

         } catch (e: Exception) {
             logger.warn(e) { "Failed to convert validation result" }
-            NanoDSLValidationResult(isValid = true) // Assume valid if conversion fails
+            NanoDSLValidationResult(
+                isValid = false,
+                errors = listOf(ValidationError("Internal error: failed to process validation result", 0)),
+                warnings = listOf("Validation result conversion failed: ${e.message}")
+            )
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt
around lines 102 to 105, the current catch block returns
NanoDSLValidationResult(isValid = true) which masks potential validation
failures; change the fallback to return isValid = false (or rethrow the
exception) and include the caught exception details in the log message so
failures are visible; specifically, replace the return with
NanoDSLValidationResult(isValid = false) and update logger.warn to include e and
a clear message, or rethrow/wrap the exception if upstream should handle
conversion failures.

Comment on lines +566 to +569
override fun renderNanoDSL(
source: String,
irJson: String?,
metadata: Map<String, String>
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all renderNanoDSL implementations
echo "=== All renderNanoDSL implementations in .kt files ==="
rg "renderNanoDSL" --type kt -B 2 | head -100

echo ""
echo "=== Search for all CodingAgentRenderer implementations ==="
rg "class.*:\s*.*CodingAgentRenderer" --type kt

echo ""
echo "=== Check CodingCliRenderer ==="
fd -type f -name "*CodingCliRenderer*" --type kt 2>/dev/null || echo "Searching for CodingCliRenderer content..."
rg "CodingCliRenderer" --type kt -l

echo ""
echo "=== Check ConsoleRenderer ==="
rg "ConsoleRenderer" --type kt -l

echo ""
echo "=== Check all renderer files ending with Renderer.kt ==="
fd -type f -name "*Renderer.kt" | sort

Repository: phodal/auto-dev

Length of output: 634


🏁 Script executed:

#!/bin/bash
# Find all renderNanoDSL implementations in Kotlin files
echo "=== All renderNanoDSL in Kotlin files ==="
rg "renderNanoDSL" --glob "*.kt" -B 2 -A 3 | head -150

echo ""
echo "=== Search for CodingAgentRenderer implementations ==="
rg "class\s+\w+.*:\s*.*CodingAgentRenderer" --glob "*.kt" -B 1

echo ""
echo "=== Find all Renderer.kt files ==="
find . -type f -name "*Renderer.kt" | head -20

echo ""
echo "=== Check if CodingCliRenderer or ConsoleRenderer exist ==="
find . -type f -name "*.kt" | xargs grep -l "CodingCliRenderer\|ConsoleRenderer" 2>/dev/null | head -20

echo ""
echo "=== Check file structure around ComposeRenderer ==="
find . -type f -path "*compose*renderer*" -name "*.kt" 2>/dev/null

Repository: phodal/auto-dev

Length of output: 7012


🏁 Script executed:

#!/bin/bash
echo "=== CodingCliRenderer content ==="
cat -n mpp-ui/src/jvmMain/kotlin/cc/unitmesh/server/cli/CodingCli.kt | head -100

echo ""
echo "=== ConsoleRenderer content ==="
cat -n mpp-ui/src/jvmMain/kotlin/cc/unitmesh/server/cli/DocumentCli.kt | head -100

echo ""
echo "=== DefaultCodingAgentRenderer ==="
cat -n mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/DefaultCodingAgentRenderer.kt 2>/dev/null || echo "File not found"

echo ""
echo "=== ServerSideRenderer ==="
cat -n mpp-server/src/main/kotlin/cc/unitmesh/server/render/ServerSideRenderer.kt | head -80

Repository: phodal/auto-dev

Length of output: 18326


🏁 Script executed:

#!/bin/bash
echo "=== Search for CodingCliRenderer class definition ==="
rg "class\s+CodingCliRenderer" --glob "*.kt" -B 2 -A 10

echo ""
echo "=== Search for ConsoleRenderer class definition ==="
rg "class\s+ConsoleRenderer" --glob "*.kt" -B 2 -A 10

echo ""
echo "=== Check ReviewCli.kt ==="
cat -n mpp-ui/src/jvmMain/kotlin/cc/unitmesh/server/cli/ReviewCli.kt 2>/dev/null | head -100 || echo "File not found"

echo ""
echo "=== Check BaseRenderer.kt for renderNanoDSL ==="
cat -n mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/BaseRenderer.kt | grep -A 5 "renderNanoDSL" || echo "No renderNanoDSL in BaseRenderer"

echo ""
echo "=== Full BaseRenderer.kt content ==="
cat -n mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/BaseRenderer.kt | head -150

Repository: phodal/auto-dev

Length of output: 12030


Update JVM CLI and server-side renderer implementations to include renderNanoDSL.

Per coding guidelines, when modifying CodingAgentRenderer, all implementations must be updated. Currently, CodingCliRenderer, ConsoleRenderer, DefaultCodingAgentRenderer, and ServerSideRenderer are missing the renderNanoDSL method that was added to ComposeRenderer and JewelRenderer in this PR.

🤖 Prompt for AI Agents
In
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt
around lines 566-569, you added renderNanoDSL but did not update other
CodingAgentRenderer implementations; add the missing override fun
renderNanoDSL(source: String, irJson: String?, metadata: Map<String, String>) to
CodingCliRenderer, ConsoleRenderer, DefaultCodingAgentRenderer, and
ServerSideRenderer with the same signature and visibility, and implement it
consistently (e.g., delegate to the class's existing render logic or to the
shared renderer method used by ComposeRenderer/JewelRenderer), ensuring it
returns the same type and behavior as the other render methods so the code
compiles and follows the established contract.

Comment on lines +424 to +440
/**
* Render generated NanoDSL UI code
* Posts a nanodsl message to the webview for rendering
*/
renderNanoDSL(source: string, irJson?: string | null, metadata?: Record<string, string>): void {
this.chatProvider.postMessage({
type: 'nanodsl',
data: {
source,
irJson,
componentName: metadata?.componentName,
attempts: metadata?.attempts ? parseInt(metadata.attempts) : 1,
isValid: metadata?.isValid === 'true',
warnings: metadata?.warnings?.split(';').filter(Boolean) || []
}
});
}
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

🧩 Analysis chain

🏁 Script executed:

cd /repo && wc -l mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 114


🏁 Script executed:

cd /repo && sed -n '498,520p' mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 114


🏁 Script executed:

cd /repo && rg "interface.*CodingAgentRenderer|class.*CodingAgentRenderer" -A 10 --type ts

Repository: phodal/auto-dev

Length of output: 114


🏁 Script executed:

pwd && git ls-files | head -20

Repository: phodal/auto-dev

Length of output: 693


🏁 Script executed:

git ls-files | grep -E "mpp-core\.ts|CodingAgentRenderer"

Repository: phodal/auto-dev

Length of output: 257


🏁 Script executed:

git ls-files | grep -E "mpp-vscode.*\.ts"

Repository: phodal/auto-dev

Length of output: 2507


🏁 Script executed:

wc -l mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 96


🏁 Script executed:

sed -n '424,440p' mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 628


🏁 Script executed:

sed -n '498,520p' mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 1450


🏁 Script executed:

cat mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt

Repository: phodal/auto-dev

Length of output: 5664


🏁 Script executed:

sed -n '1,50p' mpp-vscode/src/bridge/mpp-core.ts

Repository: phodal/auto-dev

Length of output: 1167


🏁 Script executed:

rg "class.*VSCodeRenderer|createKotlinRenderer" mpp-vscode/src/bridge/mpp-core.ts -B 3 -A 1

Repository: phodal/auto-dev

Length of output: 558


Forward renderNanoDSL through the Kotlin renderer adapter

VSCodeRenderer.renderNanoDSL(...) posts nanodsl messages to the webview, but createKotlinRenderer() does not expose this method on the adapter object passed to JsCodingAgent. If the Kotlin side calls renderNanoDSL(...) on its renderer, the call will be undefined and VSCode will not receive NanoDSL events.

Add the forwarding:

   private createKotlinRenderer(): any {
     const renderer = this.renderer;
     return {
       renderIterationHeader: (c: number, m: number) => renderer.renderIterationHeader(c, m),
       renderLLMResponseStart: () => renderer.renderLLMResponseStart(),
       renderLLMResponseChunk: (chunk: string) => renderer.renderLLMResponseChunk(chunk),
       renderLLMResponseEnd: () => renderer.renderLLMResponseEnd(),
       renderToolCall: (name: string, params: string) => renderer.renderToolCall(name, params),
       renderToolResult: (name: string, success: boolean, output: string | null, full: string | null) =>
         renderer.renderToolResult(name, success, output, full),
       renderTaskComplete: (executionTimeMs?: number, toolsUsedCount?: number) => renderer.renderTaskComplete(executionTimeMs, toolsUsedCount),
       renderFinalResult: (success: boolean, msg: string, iters: number) =>
         renderer.renderFinalResult(success, msg, iters),
       renderError: (msg: string) => renderer.renderError(msg),
       renderRepeatWarning: (name: string, count: number) => renderer.renderRepeatWarning(name, count),
       renderRecoveryAdvice: (advice: string) => renderer.renderRecoveryAdvice(advice),
+      renderNanoDSL: (source: string, irJson?: string | null, metadata?: Record<string, string>) =>
+        renderer.renderNanoDSL(source, irJson, metadata),
       renderUserConfirmationRequest: (name: string, params: any) =>
         renderer.renderUserConfirmationRequest(name, params),
       forceStop: () => renderer.forceStop()
     };
   }

This keeps the JS bridge synchronized with the CodingAgentRenderer interface so VSCode can render NanoDSL items. This is required per the coding guidelines for VSCode implementations whenever CodingAgentRenderer is extended.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In mpp-vscode/src/bridge/mpp-core.ts around lines 424 to 440, the Kotlin
renderer adapter returned by createKotlinRenderer does not forward renderNanoDSL
to the underlying VSCodeRenderer, so calls from the Kotlin side will be
undefined; add a renderNanoDSL(source, irJson?, metadata?) method on the adapter
that simply delegates to this.chatProvider.renderNanoDSL /
this.chatProvider.postMessage equivalent (i.e., call the existing VSCode
renderer's renderNanoDSL implementation or post the same 'nanodsl' message
structure used elsewhere), preserving the metadata parsing (attempts, isValid,
warnings) exactly as in the current renderNanoDSL implementation so the adapter
matches the CodingAgentRenderer interface.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements validation/retry mechanisms and UI rendering integration for the NanoDSLAgent, enabling AI-generated UI code validation with automatic error correction and comprehensive cross-platform rendering support.

Key Changes:

  • Validation Infrastructure: Multi-platform NanoDSLValidator with JVM full parsing (via reflection to xuiper-ui) and basic syntax validation for JS/WASM/iOS/Android
  • Retry Mechanism: NanoDSLAgent now validates generated code and retries up to 3 times with error feedback for LLM self-correction
  • Rendering Integration: New renderNanoDSL() method added to CodingAgentRenderer interface with implementations across 6 platforms (VSCode, CLI, TUI, Server, Compose, IntelliJ)

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.kt Defines expect class with validation/parse interfaces and result types
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.jvm.kt JVM implementation using reflection to access xuiper-ui's NanoParser with fallback to basic validation
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.android.kt Android implementation mirroring JVM approach with reflection-based parsing
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.js.kt JavaScript implementation with basic syntax validation (no AST parsing)
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.wasmJs.kt WASM implementation with basic syntax validation
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/parser/NanoDSLValidator.ios.kt iOS implementation with basic syntax validation
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt Enhanced with retry loop, validation integration, error feedback prompts, and metadata generation
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt Added renderNanoDSL() interface method with default no-op implementation
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererModels.kt Added TimelineItem.NanoDSLItem data class for timeline integration
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/RendererExports.kt Added JsNanoDSLData export class and JS renderer adapter integration
mpp-vscode/src/bridge/mpp-core.ts VSCode renderer implementation posting nanodsl messages to webview
mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts CLI renderer with syntax-highlighted NanoDSL code display
mpp-ui/src/jsMain/typescript/agents/render/TuiRenderer.ts TUI renderer displaying NanoDSL in markdown code blocks
mpp-ui/src/jsMain/typescript/agents/render/ServerRenderer.ts Server renderer with formatted code and line numbers
mpp-ui/src/jsMain/typescript/agents/render/BaseRenderer.ts Added base renderNanoDSL() method for inheritance
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/ComposeRenderer.kt Compose renderer creating NanoDSLItem timeline entries
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt Added NanoDSLTimelineItem composable component for UI display
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt IntelliJ Jewel renderer adding NanoDSLItem to timeline
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt New IntelliJ bubble component for displaying NanoDSL code with Jewel theming
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt Timeline integration routing NanoDSLItem to bubble component
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/knowledge/IdeaKnowledgeContent.kt Knowledge panel display for NanoDSL items
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/compose/IdeaComposeEffects.kt Added IdeaCircularProgressIndicator to avoid ClassLoader conflicts
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/*.kt Replaced Jewel CircularProgressIndicator with custom implementation
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/MermaidDiagramView.kt Updated to use IdeaCircularProgressIndicator
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt Updated progress indicators to avoid conflicts
.idea/runConfigurations/RunIDEA.xml Fixed Gradle task path for IDEA run configuration
Files not reviewed (1)
  • .idea/runConfigurations/RunIDEA.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 76 to 165
for (attempt in 1..maxRetries) {
try {
val prompt = if (attempt == 1) {
buildPrompt(input)
} else {
// Include previous errors in retry prompt
buildRetryPrompt(input, lastGeneratedCode, lastErrors)
}

onProgress(if (attempt == 1) {
"Calling LLM for code generation..."
} else {
"Retry attempt $attempt/$maxRetries - fixing validation errors..."
})

val responseBuilder = StringBuilder()
llmService.streamPrompt(
userPrompt = prompt,
compileDevIns = false
).toList().forEach { chunk ->
responseBuilder.append(chunk)
}

val llmResponse = responseBuilder.toString()

// Extract NanoDSL code from markdown code fence
val codeFence = CodeFence.parse(llmResponse)
val generatedCode = if (codeFence.text.isNotBlank()) {
codeFence.text.trim()
} else {
llmResponse.trim()
}

lastGeneratedCode = generatedCode

// Validate the generated code
val validationResult = validator.validate(generatedCode)

if (validationResult.isValid) {
// Try to parse and get IR JSON
val parseResult = validator.parse(generatedCode)
if (parseResult is NanoDSLParseResult.Success) {
irJson = parseResult.irJson
}

onProgress("✅ Generated ${generatedCode.lines().size} lines of valid NanoDSL code" +
(if (attempt > 1) " (after $attempt attempts)" else ""))

// Log warnings if any
if (validationResult.warnings.isNotEmpty()) {
validationResult.warnings.forEach { warning ->
onProgress("⚠️ $warning")
}
}

return ToolResult.AgentResult(
success = true,
content = generatedCode,
metadata = buildMetadata(input, generatedCode, attempt, irJson, validationResult)
)
} else {
// Validation failed, prepare for retry
lastErrors = validationResult.errors
val errorMessages = validationResult.errors.joinToString("\n") {
"Line ${it.line}: ${it.message}" + (it.suggestion?.let { s -> " ($s)" } ?: "")
}

if (attempt < maxRetries) {
onProgress("⚠️ Validation failed, will retry: $errorMessages")
logger.warn { "NanoDSL validation failed (attempt $attempt): $errorMessages" }
} else {
onProgress("❌ Validation failed after $maxRetries attempts: $errorMessages")
logger.error { "NanoDSL validation failed after all retries: $errorMessages" }
}
}
} catch (e: Exception) {
logger.error(e) { "NanoDSL generation failed on attempt $attempt" }
if (attempt == maxRetries) {
onProgress("❌ Generation failed: ${e.message}")
return ToolResult.AgentResult(
success = false,
content = "Failed to generate NanoDSL: ${e.message}",
metadata = mapOf(
"error" to (e.message ?: "Unknown error"),
"attempts" to attempt.toString()
)
)
}
}
}
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The retry loop doesn't include a delay between attempts. When the LLM generates invalid code, immediately retrying without any backoff can:

  1. Waste resources on rapid repeated failures
  2. Not give the LLM's internal state time to "reset" if it's in a failure mode
  3. Result in identical errors if the issue is deterministic

Consider adding a small delay (e.g., 500ms-1s) between retry attempts, or at least documenting why immediate retry is preferred.

Copilot uses AI. Check for mistakes.
Comment on lines +183 to +209
private fun buildRetryPrompt(
input: NanoDSLContext,
previousCode: String,
errors: List<ValidationError>
): String {
val errorFeedback = buildString {
appendLine("## Previous Attempt (INVALID)")
appendLine("```nanodsl")
appendLine(previousCode)
appendLine("```")
appendLine()
appendLine("## Validation Errors to Fix:")
errors.forEach { error ->
appendLine("- Line ${error.line}: ${error.message}")
error.suggestion?.let { appendLine(" Suggestion: $it") }
}
appendLine()
appendLine("## Instructions:")
appendLine("Please fix the above errors and generate a corrected version.")
appendLine("Output ONLY the corrected NanoDSL code, no explanations.")
}

onProgress("✅ Generated ${generatedCode.lines().size} lines of NanoDSL code")

ToolResult.AgentResult(
success = true,
content = generatedCode,
metadata = mapOf(
"description" to input.description,
"componentType" to (input.componentType ?: "auto"),
"linesOfCode" to generatedCode.lines().size.toString(),
"includesState" to input.includeState.toString(),
"includesHttp" to input.includeHttp.toString()
)
)
} catch (e: Exception) {
logger.error(e) { "NanoDSL generation failed" }
onProgress("❌ Generation failed: ${e.message}")

ToolResult.AgentResult(
success = false,
content = "Failed to generate NanoDSL: ${e.message}",
metadata = mapOf("error" to (e.message ?: "Unknown error"))
)
return """
${buildPrompt(input)}

$errorFeedback
""".trim()
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The retry prompt includes the full previous invalid code and all errors, which could consume significant token budget for large generated code blocks or multiple retries. Consider:

  1. Including only the most critical errors (e.g., first 3-5)
  2. Truncating very long code blocks in the retry prompt
  3. Using a more concise error format

For example, if the first attempt generates 500 lines of code with 20 errors, the second attempt's prompt would be extremely long, and the third attempt even longer.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The showPreview state variable is declared but never used. The NanoDSL bubble component doesn't implement any preview toggle functionality despite the state management being in place.

Either:

  1. Remove the unused variable if preview functionality isn't planned
  2. Implement the preview toggle UI if it's intended for future use
  3. Add a TODO comment explaining the planned preview feature
Suggested change
var showPreview by remember { mutableStateOf(false) }

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +106
for (line in lines) {
for (char in line) {
when (char) {
'(' -> parenCount++
')' -> parenCount--
'{' -> braceCount++
'}' -> braceCount--
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Negative bracket/parenthesis counts are not detected as errors. The current logic only checks if counts are non-zero at the end, but doesn't catch cases where closing brackets appear before opening ones (e.g., "text)" or "}value").

Consider tracking and reporting when counts go negative:

if (parenCount < 0) {
    errors.add(ValidationError("Unexpected closing parenthesis", lineNum))
    parenCount = 0 // Reset to continue checking
}
Suggested change
for (line in lines) {
for (char in line) {
when (char) {
'(' -> parenCount++
')' -> parenCount--
'{' -> braceCount++
'}' -> braceCount--
for ((lineNum, line) in lines.withIndex()) {
for (char in line) {
when (char) {
'(' -> parenCount++
')' -> {
parenCount--
if (parenCount < 0) {
errors.add(ValidationError(
"Unexpected closing parenthesis",
lineNum + 1,
"Found ')' before matching '('"
))
parenCount = 0 // Reset to continue checking
}
}
'{' -> braceCount++
'}' -> {
braceCount--
if (braceCount < 0) {
errors.add(ValidationError(
"Unexpected closing brace",
lineNum + 1,
"Found '}' before matching '{'"
))
braceCount = 0 // Reset to continue checking
}
}

Copilot uses AI. Check for mistakes.
*/
private fun createSourceOnlyIR(source: String): String {
// Extract component name from source
val componentNameMatch = Regex("""component\s+(\w+):""").find(source)
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The regex pattern for extracting the component name uses \w+ which matches word characters including underscores and digits. However, component names starting with digits (e.g., component 123Test:) would be matched but are likely invalid identifiers in most languages.

Consider using a more restrictive pattern like [A-Z][a-zA-Z0-9]* to match typical PascalCase component names, or document that the validation accepts any word characters.

Suggested change
val componentNameMatch = Regex("""component\s+(\w+):""").find(source)
val componentNameMatch = Regex("""component\s+([A-Z][a-zA-Z0-9]*):""").find(source)

Copilot uses AI. Check for mistakes.
}

is TimelineItem.NanoDSLItem -> {
// NanoDSL items are not persisted (they're runtime-only, can be regenerated)
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The documentation comment states "NanoDSL items are not persisted (they're runtime-only, can be regenerated)" but doesn't explain the reasoning. This decision could lead to data loss if users expect their generated UI code to persist across sessions.

Consider:

  1. Adding a more detailed explanation of why NanoDSL items aren't persisted
  2. Documenting the expected workflow for users who want to save the generated code
  3. Adding a user-facing warning or export option if persistence is important
Suggested change
// NanoDSL items are not persisted (they're runtime-only, can be regenerated)
/**
* NanoDSL items are not persisted.
*
* Reasoning: NanoDSL items represent generated UI code that is derived from other timeline/context data.
* Persisting them could lead to inconsistencies if the underlying data changes, and they can always be regenerated
* from the source information. This design avoids storing potentially stale or redundant UI code.
*
* Expected workflow: If users want to save generated UI code, they should explicitly export or save the code
* at the time of generation. NanoDSL items will not be available after a session ends unless exported.
*
* If persistence of generated UI code is important, consider providing a user-facing warning or an export option
* in the UI to prevent accidental data loss.
*/

Copilot uses AI. Check for mistakes.
Comment on lines +837 to +842
text = item.source.take(300) + if (item.source.length > 300) "..." else "",
style = JewelTheme.defaultTextStyle.copy(
fontSize = 11.sp,
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace
)
)
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The NanoDSL code display in the Knowledge Content truncates at 300 characters with "..." but doesn't provide any way to view the full code. This could be frustrating for users who want to see their complete generated UI code.

Consider adding:

  1. A "Show More" button or expandable section
  2. A "Copy Code" button
  3. A modal/dialog to view the full code
  4. Or increase the character limit to a more reasonable value like 1000

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +151
private fun performBasicValidation(source: String): NanoDSLValidationResult {
val errors = mutableListOf<ValidationError>()
val warnings = mutableListOf<String>()
val lines = source.lines()

// Check for component definition
val hasComponentDef = lines.any { it.trim().startsWith("component ") && it.trim().endsWith(":") }
if (!hasComponentDef) {
errors.add(ValidationError(
"Missing component definition. Expected 'component Name:'",
0,
"Add 'component YourComponentName:' at the start"
))
}

// Check indentation consistency
for ((lineNum, line) in lines.withIndex()) {
if (line.isBlank()) continue

val indent = line.takeWhile { it == ' ' }.length

// Check for tabs (not allowed)
if (line.contains('\t')) {
errors.add(ValidationError(
"Tabs are not allowed. Use 4 spaces for indentation.",
lineNum,
"Replace tabs with 4 spaces"
))
}

// Check for odd indentation (should be multiple of 4)
if (indent % 4 != 0) {
warnings.add("Line ${lineNum + 1}: Indentation should be a multiple of 4 spaces")
}
}

// Check for known components
val knownComponents = setOf(
"VStack", "HStack", "Card", "Text", "Button", "Input", "Image",
"Badge", "Checkbox", "Toggle", "Select", "List", "Grid",
"Spacer", "Divider", "Form", "Section"
)

for ((lineNum, line) in lines.withIndex()) {
val trimmed = line.trim()

// Check for component-like patterns
val componentMatch = Regex("""^(\w+)(?:\(.*\))?:\s*$""").find(trimmed)
if (componentMatch != null) {
val componentName = componentMatch.groupValues[1]
if (componentName !in knownComponents &&
componentName != "component" &&
componentName != "state" &&
componentName != "if" &&
componentName != "for" &&
componentName != "on_click" &&
componentName != "content") {
warnings.add("Line ${lineNum + 1}: Unknown component '$componentName'")
}
}
}

// Check for unclosed blocks
var parenCount = 0
var braceCount = 0
for (line in lines) {
for (char in line) {
when (char) {
'(' -> parenCount++
')' -> parenCount--
'{' -> braceCount++
'}' -> braceCount--
}
}
}

if (parenCount != 0) {
errors.add(ValidationError(
"Unbalanced parentheses",
0,
"Check for missing '(' or ')'"
))
}

if (braceCount != 0) {
errors.add(ValidationError(
"Unbalanced braces",
0,
"Check for missing '{' or '}'"
))
}

return NanoDSLValidationResult(
isValid = errors.isEmpty(),
errors = errors,
warnings = warnings
)
}

/**
* Create a source-only IR JSON for non-JVM platforms
*/
private fun createSourceOnlyIR(source: String): String {
// Extract component name from source
val componentNameMatch = Regex("""component\s+(\w+):""").find(source)
val componentName = componentNameMatch?.groupValues?.get(1) ?: "UnknownComponent"

// Escape the source for JSON
val escapedSource = source
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")

return """{"type":"Component","props":{"name":"$componentName"},"source":"$escapedSource"}"""
}
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The code validation across platform implementations (JS, WASM, iOS, Android, JVM) contains significant duplication. Consider extracting the common performBasicValidation and createSourceOnlyIR/createMinimalIR functions into a shared common module source set.

This duplication makes maintenance harder - a bug fix or feature addition would need to be replicated across 5 files. The validation logic appears identical across platforms, making this an ideal candidate for code reuse.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +125
// Check for unclosed blocks
var parenCount = 0
var braceCount = 0
for (line in lines) {
for (char in line) {
when (char) {
'(' -> parenCount++
')' -> parenCount--
'{' -> braceCount++
'}' -> braceCount--
}
}
}

if (parenCount != 0) {
errors.add(ValidationError(
"Unbalanced parentheses",
0,
"Check for missing '(' or ')'"
))
}

if (braceCount != 0) {
errors.add(ValidationError(
"Unbalanced braces",
0,
"Check for missing '{' or '}'"
))
}
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The bracket validation logic doesn't account for brackets inside string literals. For example, Text("Hello (world)") would be incorrectly flagged for unbalanced parentheses even though they're inside a string.

While full string parsing is complex, at minimum this should be documented as a known limitation in the function's documentation comment.

Copilot uses AI. Check for mistakes.
Comment on lines +657 to +682
let result = line;

// Highlight strings (quoted text)
result = result.replace(/"([^"]*)"/g, (match) => semanticChalk.success(match));

// Highlight keywords
for (const keyword of keywords) {
const regex = new RegExp(`\\b(${keyword})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.primary(match));
}

// Highlight components
for (const comp of components) {
const regex = new RegExp(`\\b(${comp})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.accent(match));
}

// Highlight types (int, str, bool)
result = result.replace(/\b(int|str|bool|float)\b/g, (match) => semanticChalk.warning(match));

// Highlight state references
result = result.replace(/\bstate\.(\w+)/g, (match, varName) =>
semanticChalk.muted('state.') + chalk.cyan(varName)
);

return result;
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The highlightNanoDSL method applies multiple regex replacements sequentially to the same string, which can lead to double-highlighting. For example, if a string contains "state.count", the string highlighting will first convert it to colored text, then the state reference regex will try to match and replace within that already-colored text, potentially breaking the ANSI codes.

Consider applying all regex patterns in a single pass, or ensure that later patterns don't match within already-replaced segments. Alternatively, document this as a known limitation.

Suggested change
let result = line;
// Highlight strings (quoted text)
result = result.replace(/"([^"]*)"/g, (match) => semanticChalk.success(match));
// Highlight keywords
for (const keyword of keywords) {
const regex = new RegExp(`\\b(${keyword})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.primary(match));
}
// Highlight components
for (const comp of components) {
const regex = new RegExp(`\\b(${comp})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.accent(match));
}
// Highlight types (int, str, bool)
result = result.replace(/\b(int|str|bool|float)\b/g, (match) => semanticChalk.warning(match));
// Highlight state references
result = result.replace(/\bstate\.(\w+)/g, (match, varName) =>
semanticChalk.muted('state.') + chalk.cyan(varName)
);
return result;
// Split line into quoted and non-quoted segments
const segments: { text: string, quoted: boolean }[] = [];
let lastIndex = 0;
const regex = /"([^"]*)"/g;
let match: RegExpExecArray | null;
while ((match = regex.exec(line)) !== null) {
if (match.index > lastIndex) {
segments.push({ text: line.slice(lastIndex, match.index), quoted: false });
}
segments.push({ text: match[0], quoted: true });
lastIndex = regex.lastIndex;
}
if (lastIndex < line.length) {
segments.push({ text: line.slice(lastIndex), quoted: false });
}
// Highlight each segment appropriately
const highlighted = segments.map(seg => {
if (seg.quoted) {
// Only apply string highlighting
return semanticChalk.success(seg.text);
} else {
let result = seg.text;
// Highlight state references
result = result.replace(/\bstate\.(\w+)/g, (match, varName) =>
semanticChalk.muted('state.') + chalk.cyan(varName)
);
// Highlight keywords
for (const keyword of keywords) {
const regex = new RegExp(`\\b(${keyword})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.primary(match));
}
// Highlight components
for (const comp of components) {
const regex = new RegExp(`\\b(${comp})\\b`, 'g');
result = result.replace(regex, (match) => semanticChalk.accent(match));
}
// Highlight types (int, str, bool, float)
result = result.replace(/\b(int|str|bool|float)\b/g, (match) => semanticChalk.warning(match));
return result;
}
});
return highlighted.join('');

Copilot uses AI. Check for mistakes.
- IdeaNanoDSLBubble.kt: Remove unused showPreview state, hoist lines variable for reuse in footer
- AgentMessageList.kt: Remove unused showPreview state, suppress unused irJson param, reuse lines variable
- NanoDSLAgent.kt: Capture exception message as pseudo-error for retry prompt context
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: 0

♻️ Duplicate comments (1)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (1)

186-212: Token budget concern already noted.

The retry prompt construction embeds full previous code and all errors. Per previous review feedback, consider truncating large code blocks or limiting error count for token efficiency.

🧹 Nitpick comments (2)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (2)

91-97: Inefficient flow collection: use collect instead of toList().forEach.

Collecting the entire flow into a list before iterating defeats the streaming benefit and buffers the full response in memory unnecessarily.

-                llmService.streamPrompt(
-                    userPrompt = prompt,
-                    compileDevIns = false
-                ).toList().forEach { chunk ->
-                    responseBuilder.append(chunk)
-                }
+                llmService.streamPrompt(
+                    userPrompt = prompt,
+                    compileDevIns = false
+                ).collect { chunk ->
+                    responseBuilder.append(chunk)
+                }

114-119: Consider logging parse failures for debugging.

When validation passes but parsing fails, the failure is silently ignored. While acceptable since IR is optional, logging the failure would aid debugging.

                 if (validationResult.isValid) {
                     // Try to parse and get IR JSON
                     val parseResult = validator.parse(generatedCode)
                     if (parseResult is NanoDSLParseResult.Success) {
                         irJson = parseResult.irJson
+                    } else if (parseResult is NanoDSLParseResult.Failure) {
+                        logger.debug { "IR parse failed despite valid syntax: ${parseResult.message}" }
                     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d14aae and 2c6d9eb.

📒 Files selected for processing (3)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (3 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/agent/AgentMessageList.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaNanoDSLBubble.kt
🧰 Additional context used
📓 Path-based instructions (2)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

**/*.kt: Use expect/actual pattern for platform-specific code (for example: Platform implementations)
Use concrete classes (not interfaces) and Promise (not Flow) for @JsExport annotations
Avoid emoji and UTF-8 characters in WASM code
When modifying CodingAgentRenderer, update ALL implementations: DefaultCodingAgentRenderer, ComposeRenderer, JewelRenderer, ServerSideRenderer, and JsRendererAdapter in Kotlin
When modifying CodingAgentRenderer, update JVM CLI implementations: CodingCliRenderer and ConsoleRenderer
Use AutoDevColors or MaterialTheme.colorScheme for Compose styling

Files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
**/*.{kt,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never use hardcoded colors - always use design tokens from the design system

Files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
🧠 Learnings (2)
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : When modifying `CodingAgentRenderer`, update JVM CLI implementations: `CodingCliRenderer` and `ConsoleRenderer`

Applied to files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
📚 Learning: 2025-12-07T08:40:10.850Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T08:40:10.850Z
Learning: Applies to **/*.kt : When modifying `CodingAgentRenderer`, update ALL implementations: `DefaultCodingAgentRenderer`, `ComposeRenderer`, `JewelRenderer`, `ServerSideRenderer`, and `JsRendererAdapter` in Kotlin

Applied to files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build
  • GitHub Check: Test mpp-core (KMP)
🔇 Additional comments (4)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/NanoDSLAgent.kt (4)

38-46: LGTM!

The constructor additions are clean - maxRetries with a sensible default and validator instantiation follow good practices for configurability.


151-167: LGTM!

Exception handling correctly distinguishes between final and non-final attempts, with appropriate logging and error reporting.


218-238: LGTM!

Clean metadata construction using buildMap with appropriate conditional inclusion of optional fields.


170-180: LGTM!

The best-effort fallback after exhausting retries is reasonable, returning whatever code was generated along with error context.

@phodal phodal merged commit d1d39c6 into master Dec 8, 2025
4 of 6 checks passed
@phodal phodal deleted the feat/nanodsl-validation-rendering branch December 8, 2025 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(NanoDSLAgent): Add validation/retry mechanism and UI rendering integration

1 participant

Comments