Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Xiiu(X=>)per
# AutoDev 3.0 - Xiu(X=>)per (Work in Progress)

> The full platform supported AI4SDLC agents.

For Autodev 2.0 (Stable version)

- branch: https://github.com/phodal/auto-dev/tree/autodev2
- Intellij Plugin: https://plugins.jetbrains.com/plugin/26988

For AutoDev 3.0 (Development version)

- Intellij Plugin: https://plugins.jetbrains.com/plugin/29223-autodev-experiment
- VSCode Extension**: [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Phodal.autodev)
- Web Version: https://phodal.github.io/auto-dev/
Expand Down
18 changes: 14 additions & 4 deletions mpp-idea/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ configurations.all {
// pty4j/jediterm - IDEA has its own terminal (~3MB)
exclude(group = "org.jetbrains.pty4j")
exclude(group = "org.jetbrains.jediterm")
// Exclude Ktor serialization modules that conflict with IntelliJ's bundled versions
exclude(group = "io.ktor", module = "ktor-serialization-kotlinx-json")
exclude(group = "io.ktor", module = "ktor-serialization-kotlinx-json-jvm")
// Note: ktor-serialization-kotlinx-json is NOT excluded globally because it's required
// by ai.koog:prompt-executor-llms-all (AbstractOpenAILLMClient) at runtime.
// It's included as an explicit dependency with coroutines excluded below.
}


Expand Down Expand Up @@ -317,7 +317,17 @@ project(":") {
compileOnly("io.ktor:ktor-client-core:3.2.2")
compileOnly("io.ktor:ktor-client-cio:3.2.2")
compileOnly("io.ktor:ktor-client-content-negotiation:3.2.2")
compileOnly("io.ktor:ktor-serialization-kotlinx-json:3.2.2")
// ktor-serialization-kotlinx-json is required at runtime by ai.koog:prompt-executor-llms-all
// (AbstractOpenAILLMClient uses JsonSupportKt for HTTP content negotiation)
// Must exclude coroutines to avoid conflicts with IntelliJ's bundled version
implementation("io.ktor:ktor-serialization-kotlinx-json:3.2.2") {
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core-jvm")
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json")
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-jvm")
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core")
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core-jvm")
}
compileOnly("io.ktor:ktor-client-logging:3.2.2")

// Use compileOnly for coroutines - IntelliJ provides these at runtime
Expand Down
558 changes: 558 additions & 0 deletions mpp-idea/mpp-idea-core/src/main/resources/META-INF/autodev-core.xml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions mpp-idea/mpp-idea-core/src/main/resources/META-INF/docker.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- Defines IDEA IDE-specific contributions and implementations. -->
<idea-plugin>
</idea-plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!-- Defines IDEA IDE-specific contributions and implementations. -->
<idea-plugin>
<extensions defaultExtensionNs="cc.unitmesh">
<jsonTextProvider implementation="cc.unitmesh.devti.provider.local.LocalJsonTextProvider"/>
</extensions>
</idea-plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package cc.unitmesh.devins.idea.tool

import cc.unitmesh.agent.tool.ExecutableTool
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
import com.intellij.openapi.project.Project
import kotlinx.coroutines.runBlocking

/**
* ToolProvider implementation for IntelliJ IDEA.
* Collects all ToolchainFunctionProvider extensions and wraps them as ExecutableTools.
*
* This bridges the gap between IDEA's extension point system and mpp-core's tool registry,
* allowing IDEA-specific tools (like database, knowledge, component view, etc.) to be
* used by CodingAgent through the unified ToolOrchestrator.
*
* @param project The IntelliJ Project context required by ToolchainFunctionProvider
*/
class IdeaToolProvider(private val project: Project) {

/**
* Provide all IDEA tools from ToolchainFunctionProvider extensions.
* This method does not require ToolDependencies as IDEA tools use Project context instead.
*/
fun provideTools(): List<ExecutableTool<*, *>> {
val providers = ToolchainFunctionProvider.all()
val tools = mutableListOf<ExecutableTool<*, *>>()

for (provider in providers) {
try {
// Get tool infos from the provider
val toolInfos = runBlocking { provider.toolInfos(project) }

// Create an adapter for each tool
for (agentTool in toolInfos) {
val adapter = ToolchainFunctionAdapter(
provider = provider,
project = project,
agentTool = agentTool
)
tools.add(adapter)
}

// If no toolInfos, try to create tools from funcNames
if (toolInfos.isEmpty()) {
val funcNames = runBlocking { provider.funcNames() }
for (funcName in funcNames) {
// Check if this provider is applicable for this function
val isApplicable = runBlocking { provider.isApplicable(project, funcName) }
Comment on lines +31 to +48
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Avoid using runBlocking in production code as it blocks the calling thread. Consider making provideTools() a suspend function or using coroutineScope with appropriate dispatchers. If this method is called from UI code, consider using IntelliJ's ProgressManager.getInstance().run() or ReadAction.nonBlocking() APIs to handle coroutines properly without blocking the thread.

Copilot uses AI. Check for mistakes.
if (isApplicable) {
val agentTool = cc.unitmesh.devti.agent.tool.AgentTool(
name = funcName,
description = "IDEA tool: $funcName",
example = "/$funcName"
)
val adapter = ToolchainFunctionAdapter(
provider = provider,
project = project,
agentTool = agentTool
)
tools.add(adapter)
}
}
}
} catch (e: Exception) {
// Log and continue with other providers
println("Warning: Failed to load tools from ${provider::class.simpleName}: ${e.message}")
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Replace println with IntelliJ Platform's Logger for consistent logging. Use Logger.getInstance(IdeaToolProvider::class.java) to create a logger instance and call logger.warn() for logging warning messages. This follows the logging pattern used elsewhere in the IDEA plugin codebase and ensures logs are properly integrated with IntelliJ's logging system.

Copilot uses AI. Check for mistakes.
}
}

return tools
}

companion object {
/**
* Create an IdeaToolProvider for the given project.
*/
fun create(project: Project): IdeaToolProvider {
return IdeaToolProvider(project)
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package cc.unitmesh.devins.idea.tool

import cc.unitmesh.agent.tool.*
import cc.unitmesh.agent.tool.schema.DeclarativeToolSchema
import cc.unitmesh.agent.tool.schema.SchemaProperty
import cc.unitmesh.agent.tool.schema.SchemaPropertyBuilder
import cc.unitmesh.agent.tool.schema.ToolCategory
import cc.unitmesh.devti.agent.tool.AgentTool
import cc.unitmesh.devti.provider.toolchain.ToolchainFunctionProvider
import com.intellij.openapi.project.Project

/**
* Parameters for ToolchainFunctionProvider execution.
* Uses a generic Map to support various parameter types from different providers.
*/
data class ToolchainFunctionParams(
val prop: String = "",
val args: List<Any> = emptyList(),
val allVariables: Map<String, Any?> = emptyMap()
)

/**
* Schema for ToolchainFunctionProvider tools.
* Provides a generic schema that accepts prop, args, and variables.
*/
class ToolchainFunctionSchema(
private val toolDescription: String,
private val example: String = ""
) : DeclarativeToolSchema(
description = toolDescription,
properties = mapOf(
"prop" to SchemaPropertyBuilder.string(
description = "Property or sub-command for the tool",
required = false
),
"args" to SchemaProperty(
type = "array",
description = "Arguments to pass to the tool",
required = false,
items = SchemaProperty(type = "string", description = "Argument value")
),
"allVariables" to SchemaProperty(
type = "object",
description = "Additional variables for the tool execution",
required = false,
additionalProperties = true
)
)
) {
override fun getExampleUsage(toolName: String): String {
return if (example.isNotEmpty()) example else "/$toolName"
}
}

/**
* Adapter that wraps a ToolchainFunctionProvider as an ExecutableTool.
* This allows IDEA-specific tools to be used in mpp-core's ToolOrchestrator.
*
* @param provider The ToolchainFunctionProvider to wrap
* @param project The IntelliJ Project context
* @param agentTool The AgentTool metadata from the provider
*/
class ToolchainFunctionAdapter(
private val provider: ToolchainFunctionProvider,
private val project: Project,
private val agentTool: AgentTool
) : BaseExecutableTool<ToolchainFunctionParams, ToolResult>() {

override val name: String = agentTool.name
override val description: String = agentTool.description

override val metadata: ToolMetadata = ToolMetadata(
displayName = agentTool.name.replace("_", " ").replaceFirstChar { it.uppercase() },
tuiEmoji = "🔧",
composeIcon = "extension",
category = ToolCategory.Utility,
schema = ToolchainFunctionSchema(agentTool.description, agentTool.example)
)

override fun getParameterClass(): String = ToolchainFunctionParams::class.simpleName ?: "ToolchainFunctionParams"

override fun createToolInvocation(params: ToolchainFunctionParams): ToolInvocation<ToolchainFunctionParams, ToolResult> {
return ToolchainFunctionInvocation(params, this, provider, project, agentTool.name)
}
}

/**
* ToolInvocation implementation for ToolchainFunctionProvider.
*/
class ToolchainFunctionInvocation(
override val params: ToolchainFunctionParams,
override val tool: ExecutableTool<ToolchainFunctionParams, ToolResult>,
private val provider: ToolchainFunctionProvider,
private val project: Project,
private val funcName: String
) : ToolInvocation<ToolchainFunctionParams, ToolResult> {

override fun getDescription(): String {
return "Execute ${tool.name} with prop='${params.prop}'"
}

override fun getToolLocations(): List<ToolLocation> = emptyList()

override suspend fun execute(context: ToolExecutionContext): ToolResult {
return try {
val result = provider.execute(
project = project,
prop = params.prop,
args = params.args,
allVariables = params.allVariables,
commandName = funcName
)

// Convert the result to ToolResult
when (result) {
is String -> ToolResult.Success(result)
is ToolResult -> result
else -> ToolResult.Success(result.toString())
}
} catch (e: Exception) {
ToolResult.Error(
message = "Failed to execute ${tool.name}: ${e.message}",
errorType = "EXECUTION_ERROR",
metadata = mapOf("exception" to (e::class.simpleName ?: "Unknown"))
)
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import cc.unitmesh.devins.compiler.service.DevInsCompilerService
import cc.unitmesh.devins.idea.compiler.IdeaDevInsCompilerService
import cc.unitmesh.devins.idea.renderer.JewelRenderer
import cc.unitmesh.devins.idea.services.IdeaToolConfigService
import cc.unitmesh.devins.idea.tool.IdeaToolProvider
import cc.unitmesh.devins.ui.config.AutoDevConfigWrapper
import cc.unitmesh.devins.ui.config.ConfigManager
import cc.unitmesh.llm.KoogLLMService
Expand Down Expand Up @@ -261,6 +262,10 @@ class IdeaAgentViewModel(
mcpToolConfigService = mcpToolConfigService,
enableLLMStreaming = true
)

// Register IDEA-specific tools from ToolchainFunctionProvider extensions
registerIdeaTools(codingAgent!!)

agentInitialized = true

// Start observing PlanStateService and sync to renderer
Expand All @@ -269,6 +274,27 @@ class IdeaAgentViewModel(
return codingAgent!!
}

/**
* Register IDEA-specific tools from ToolchainFunctionProvider extensions.
* This bridges IDEA's extension point system with mpp-core's tool registry.
*/
private fun registerIdeaTools(agent: CodingAgent) {
try {
val ideaToolProvider = IdeaToolProvider.create(project)
val ideaTools = ideaToolProvider.provideTools()

for (tool in ideaTools) {
agent.registerTool(tool)
}

if (ideaTools.isNotEmpty()) {
println("Registered ${ideaTools.size} IDEA tools from ToolchainFunctionProvider extensions")
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Replace println with IntelliJ Platform's Logger for consistent logging. Use Logger.getInstance(IdeaAgentViewModel::class.java) to create a logger instance and call logger.info() or logger.warn() methods for logging messages. This follows the logging pattern used elsewhere in the IDEA plugin codebase and ensures logs are properly integrated with IntelliJ's logging system.

Copilot uses AI. Check for mistakes.
}
} catch (e: Exception) {
println("Warning: Failed to register IDEA tools: ${e.message}")
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Replace println with IntelliJ Platform's Logger for consistent logging. Use Logger.getInstance(IdeaAgentViewModel::class.java) to create a logger instance and call logger.warn() for logging warning messages. This follows the logging pattern used elsewhere in the IDEA plugin codebase.

Copilot uses AI. Check for mistakes.
}
}

// Job for observing PlanStateService
private var planStateObserverJob: Job? = null

Expand Down
Loading