Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit873c8e7

Browse files
committed
feat(AgentsInsCommand): add command for listing and invoking AI agents andclosed#451
1 parent2d088d0 commit873c8e7

File tree

6 files changed

+370
-4
lines changed

6 files changed

+370
-4
lines changed

‎core/src/main/kotlin/cc/unitmesh/devti/command/dataprovider/BuiltinCommand.kt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ enum class BuiltinCommand(
229229
true,
230230
enableInSketch=true
231231
),
232+
AGENTS(
233+
"agents",
234+
"List all available AI agents or invoke a specific agent. Without parameters, displays all available agents including A2A agents and DevIns agents. With agent name parameter, invokes the specified agent for task execution.",
235+
AutoDevIcons.CLOUD_AGENT,
236+
true,
237+
false,
238+
enableInSketch=true
239+
),
232240
;
233241

234242
companionobject {

‎exts/devins-lang/src/main/kotlin/cc/unitmesh/devti/language/compiler/exec/agents/A2AInsCommand.kt‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import kotlinx.serialization.json.Json
1212
/**
1313
* A2A (Agent-to-Agent) command implementation for sending messages to A2A protocol agents.
1414
*
15-
* Usage:
16-
* - JSON format: /a2a with JSON code block
17-
* - Legacy format: /a2a <agent_name> "<message>"
18-
*
1915
* Example:
2016
* ```json
2117
* {
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
packagecc.unitmesh.devti.language.compiler.exec.agents
2+
3+
importcc.unitmesh.devti.a2a.A2AService
4+
importcc.unitmesh.devti.a2a.A2ASketchToolchainProvider
5+
importcc.unitmesh.devti.command.InsCommand
6+
importcc.unitmesh.devti.command.dataprovider.BuiltinCommand
7+
importcc.unitmesh.devti.language.compiler.error.DEVINS_ERROR
8+
importcc.unitmesh.devti.provider.DevInsAgentToolCollector
9+
importcom.intellij.openapi.project.Project
10+
importkotlinx.serialization.Serializable
11+
importkotlinx.serialization.SerializationException
12+
importkotlinx.serialization.json.Json
13+
14+
/**
15+
* Request format for agents command
16+
*/
17+
@Serializable
18+
data classAgentRequest(
19+
valagent:String,
20+
valmessage:String
21+
)
22+
23+
/**
24+
* Agents command implementation for listing and invoking AI agents.
25+
*
26+
* Usage:
27+
* - List all agents: /agents
28+
* - JSON format: /agents with JSON code block
29+
* - Legacy format: /agents <agent_name> "<message>"
30+
*
31+
* Example:
32+
* ```devin
33+
* /agents
34+
* ```
35+
*
36+
* Or invoke an agent with JSON:
37+
* ```devin
38+
* /agents
39+
* ```json
40+
* {
41+
* "agent": "code-reviewer",
42+
* "message": "Please review this code"
43+
* }
44+
* ```
45+
* ```
46+
*
47+
* Or use legacy format:
48+
* ```devin
49+
* /agents code-reviewer "Please review this code"
50+
* ```
51+
*/
52+
classAgentsInsCommand(
53+
privatevalproject:Project,
54+
privatevalprop:String,
55+
privatevalcodeContent:String
56+
) : InsCommand {
57+
overrideval commandName:BuiltinCommand=BuiltinCommand.AGENTS
58+
59+
overridefunisApplicable():Boolean=true
60+
61+
overridesuspendfunexecute():String? {
62+
// If no parameter and no code content, list all agents
63+
if (prop.isBlank()&& codeContent.isBlank()) {
64+
return listAllAgents()
65+
}
66+
67+
// Parse request from JSON or legacy format
68+
val request= parseRequest(prop, codeContent)
69+
if (request==null) {
70+
return"${DEVINS_ERROR} Invalid request format. Use JSON: {\"agent\":\"agent-name\",\"message\":\"your message\"} or legacy format: agent-name\"message\""
71+
}
72+
73+
if (request.agent.isEmpty()) {
74+
return"${DEVINS_ERROR} Agent name is required."
75+
}
76+
77+
if (request.message.isEmpty()) {
78+
return"${DEVINS_ERROR} Message is required."
79+
}
80+
81+
// Invoke the specific agent
82+
return invokeAgent(request.agent, request.message)
83+
}
84+
85+
/**
86+
* List all available agents including A2A agents and DevIns agents
87+
*/
88+
privatefunlistAllAgents():String {
89+
val result=StringBuilder()
90+
result.append("Available AI Agents:\n\n")
91+
92+
// Collect A2A agents
93+
val a2aAgents=try {
94+
A2ASketchToolchainProvider.collectA2ATools(project)
95+
}catch (e:Exception) {
96+
emptyList()
97+
}
98+
99+
if (a2aAgents.isNotEmpty()) {
100+
result.append("## A2A Agents\n")
101+
a2aAgents.forEach { agent->
102+
result.append("- **${agent.name}**")
103+
if (agent.description.isNotEmpty()) {
104+
result.append(":${agent.description}")
105+
}
106+
result.append("\n")
107+
}
108+
result.append("\n")
109+
}
110+
111+
// Collect DevIns agents
112+
val devInsAgents=try {
113+
DevInsAgentToolCollector.all(project)
114+
}catch (e:Exception) {
115+
emptyList()
116+
}
117+
118+
if (devInsAgents.isNotEmpty()) {
119+
result.append("## DevIns Agents\n")
120+
devInsAgents.forEach { agent->
121+
result.append("- **${agent.name}**")
122+
if (agent.description.isNotEmpty()) {
123+
result.append(":${agent.description}")
124+
}
125+
if (agent.devinScriptPath.isNotEmpty()) {
126+
result.append(" (${agent.devinScriptPath})")
127+
}
128+
result.append("\n")
129+
}
130+
result.append("\n")
131+
}
132+
133+
if (a2aAgents.isEmpty()&& devInsAgents.isEmpty()) {
134+
result.append("No agents available. Please configure A2A agents or create DevIns agents.\n")
135+
}else {
136+
result.append("Total:${a2aAgents.size+ devInsAgents.size} agent(s)\n")
137+
}
138+
139+
return result.toString()
140+
}
141+
142+
/**
143+
* Parse request from JSON or legacy format
144+
*/
145+
privatefunparseRequest(prop:String,codeContent:String):AgentRequest? {
146+
// Try JSON format first
147+
if (codeContent.isNotBlank()) {
148+
try {
149+
returnJson.Default.decodeFromString<AgentRequest>(codeContent)
150+
}catch (e:Exception) {
151+
// Fallback to legacy format if JSON parsing fails
152+
}
153+
}
154+
155+
// Legacy string format: "agent-name \"message\"" or "agent-name message"
156+
if (prop.isBlank())returnnull
157+
158+
val (agentName, message)= parseCommand(prop)
159+
returnif (agentName.isNotEmpty()) {
160+
AgentRequest(agentName, message)
161+
}else {
162+
null
163+
}
164+
}
165+
166+
/**
167+
* Parse the command string to extract agent name and message.
168+
* Expected format: "<agent_name> \"<message>\"" or "<agent_name> <message>"
169+
*/
170+
privatefunparseCommand(input:String):Pair<String,String> {
171+
val trimmed= input.trim()
172+
173+
if (trimmed.isEmpty()) {
174+
returnPair("","")
175+
}
176+
177+
// Try to parse quoted message first
178+
val quotedMessageRegex="""^(\S+)\s+"(.+)"$""".toRegex()
179+
val quotedMatch= quotedMessageRegex.find(trimmed)
180+
if (quotedMatch!=null) {
181+
val agentName= quotedMatch.groupValues[1]
182+
val message= quotedMatch.groupValues[2]
183+
returnPair(agentName, message)
184+
}
185+
186+
// Try to parse single quoted message
187+
val singleQuotedRegex="""^(\S+)\s+'(.+)'$""".toRegex()
188+
val singleQuotedMatch= singleQuotedRegex.find(trimmed)
189+
if (singleQuotedMatch!=null) {
190+
val agentName= singleQuotedMatch.groupValues[1]
191+
val message= singleQuotedMatch.groupValues[2]
192+
returnPair(agentName, message)
193+
}
194+
195+
// Fallback: split by first space
196+
val parts= trimmed.split("", limit=2)
197+
if (parts.size>=2) {
198+
returnPair(parts[0], parts[1])
199+
}elseif (parts.size==1) {
200+
returnPair(parts[0],"")
201+
}
202+
203+
returnPair("","")
204+
}
205+
206+
/**
207+
* Invoke a specific agent by name
208+
*/
209+
privatesuspendfuninvokeAgent(agentName:String,input:String):String? {
210+
// Try to find and invoke A2A agent first
211+
val a2aService= project.getService(A2AService::class.java)
212+
a2aService.initialize()
213+
214+
if (a2aService.isAvailable()) {
215+
// Check if the agent exists in A2A agents by trying to send a message
216+
try {
217+
val response= a2aService.sendMessage(agentName, input)
218+
if (response!=null) {
219+
return"A2A Agent '$agentName' response:\n$response"
220+
}
221+
// If response is null, continue to try DevIns agents
222+
}catch (e:Exception) {
223+
// If error occurs, continue to try DevIns agents
224+
}
225+
}
226+
227+
// Try to find and invoke DevIns agent
228+
val devInsAgents=DevInsAgentToolCollector.all(project)
229+
val devInsAgent= devInsAgents.find { it.name== agentName }
230+
231+
if (devInsAgent!=null) {
232+
returntry {
233+
val collectors= com.intellij.openapi.extensions.ExtensionPointName
234+
.create<DevInsAgentToolCollector>("cc.unitmesh.devInsAgentTool")
235+
.extensionList
236+
237+
for (collectorin collectors) {
238+
val result= collector.execute(project, agentName, input)
239+
if (result!=null) {
240+
return"DevIns Agent '$agentName' response:\n$result"
241+
}
242+
}
243+
244+
"${DEVINS_ERROR} Failed to execute DevIns agent '$agentName'"
245+
}catch (e:Exception) {
246+
"${DEVINS_ERROR} Error executing DevIns agent '$agentName':${e.message}"
247+
}
248+
}
249+
250+
// Agent not found
251+
return"${DEVINS_ERROR} Agent '$agentName' not found. Use /agents to list all available agents."
252+
}
253+
}
254+

‎exts/devins-lang/src/main/kotlin/cc/unitmesh/devti/language/compiler/processor/InsCommandFactory.kt‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import cc.unitmesh.devti.command.dataprovider.BuiltinCommand
66
importcc.unitmesh.devti.command.dataprovider.BuiltinCommand.Companion.toolchainProviderName
77
importcc.unitmesh.devti.language.compiler.exec.*
88
importcc.unitmesh.devti.language.compiler.exec.agents.A2AInsCommand
9+
importcc.unitmesh.devti.language.compiler.exec.agents.AgentsInsCommand
910
importcc.unitmesh.devti.language.compiler.exec.file.DirInsCommand
1011
importcc.unitmesh.devti.language.compiler.exec.file.EditFileInsCommand
1112
importcc.unitmesh.devti.language.compiler.exec.file.FileInsCommand
@@ -181,6 +182,11 @@ class InsCommandFactory {
181182
val shireCode:String?= lookupNextCode(used)?.codeText()
182183
A2AInsCommand(context.project, prop, shireCode?:"")
183184
}
185+
BuiltinCommand.AGENTS-> {
186+
context.result.isLocalCommand=true
187+
val shireCode:String?= lookupNextCode(used)?.codeText()
188+
AgentsInsCommand(context.project, prop, shireCode?:"")
189+
}
184190
BuiltinCommand.TOOLCHAIN_COMMAND-> {
185191
context.result.isLocalCommand=true
186192
createToolchainCommand(used, prop, originCmdName, commandNode, context)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/agents
2+
3+
List all available agents.
4+
5+
Or invoke a specific agent with JSON format:
6+
/agents
7+
```json
8+
{
9+
"agent": "code-reviewer",
10+
"message": "Please review this code for potential security vulnerabilities"
11+
}
12+
```

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp