package cc.unitmesh.agent.tool
import cc.unitmesh.agent.tool.schema.ToolCategory
import cc.unitmesh.agent.tool.schema.ToolSchema
import kotlinx.serialization.Serializable
/**
* Base interface for all tools in the Agent system.
* Tools provide specific functionality that can be invoked by agents.
*/
interface Tool {
val name: String
val description: String
}
/**
* Metadata for a tool including UI/display information
*/
data class ToolMetadata(
val displayName: String,
val tuiEmoji: String,
val composeIcon: String,
val category: ToolCategory,
val schema: ToolSchema
)
/**
* Serializable representation of an agent tool with metadata
*/
@Serializable
data class AgentTool(
override val name: String,
override val description: String,
val example: String = "",
val isMcp: Boolean = false,
val completion: String = "",
val mcpGroup: String = "",
val isDevIns: Boolean = false,
val devinScriptPath: String = "",
) : Tool {
override fun toString(): String {
val descAttr = if (description.isNotEmpty()) " description=\"$description\"" else ""
val exampleContent = if (example.isNotEmpty()) """
$example
""" else ""
return """$exampleContent
"""
}
}
/**
* Result of a tool execution
*/
@Serializable
sealed class ToolResult {
@Serializable
data class Success(val content: String, val metadata: Map = emptyMap()) : ToolResult()
@Serializable
data class Error(
val message: String,
val errorType: String = "UNKNOWN",
val metadata: Map = emptyMap()
) : ToolResult()
/**
* Agent 结果 - 包含结构化数据
* 用于 Agent 执行结果,可以携带额外的元数据
*/
@Serializable
data class AgentResult(
val success: Boolean,
val content: String,
val metadata: Map = emptyMap()
) : ToolResult()
/**
* Pending 结果 - 表示异步执行中的工具调用
* 用于 Shell 等需要实时输出的工具,UI 可以通过 sessionId 跟踪执行状态
*
* @param sessionId 会话 ID,用于跟踪和更新执行状态
* @param toolName 工具名称
* @param command 执行的命令(用于显示)
* @param message 状态消息
* @param metadata 额外的元数据
*/
@Serializable
data class Pending(
val sessionId: String,
val toolName: String,
val command: String = "",
val message: String = "Executing...",
val metadata: Map = emptyMap()
) : ToolResult()
fun isSuccess(): Boolean = this is Success || (this is AgentResult && this.success)
fun isError(): Boolean = this is Error || (this is AgentResult && !this.success)
fun isPending(): Boolean = this is Pending
fun getOutput(): String = when (this) {
is Success -> content
is AgentResult -> content
is Error -> ""
is Pending -> message
}
fun getError(): String = when (this) {
is Success -> ""
is AgentResult -> if (!success) content else ""
is Error -> message
is Pending -> ""
}
fun extractMetadata(): Map = when (this) {
is Success -> metadata
is AgentResult -> metadata
is Error -> metadata
is Pending -> metadata
}
}
/**
* Represents a location that a tool will affect (file path, directory, etc.)
*/
@Serializable
data class ToolLocation(
val path: String,
val type: LocationType = LocationType.FILE
)
@Serializable
enum class LocationType {
FILE,
DIRECTORY,
URL,
OTHER
}
/**
* Parameters for tool execution context
*/
data class ToolExecutionContext(
val workingDirectory: String? = null,
val environment: Map = emptyMap(),
val timeout: Long = 30000L, // 30 seconds default
val metadata: Map = emptyMap()
)
/**
* Represents a validated and ready-to-execute tool call.
* Similar to Gemini CLI's ToolInvocation interface.
*/
interface ToolInvocation {
/**
* The validated parameters for this specific invocation.
*/
val params: TParams
/**
* The tool that created this invocation
*/
val tool: ExecutableTool
/**
* Gets a pre-execution description of the tool operation.
*/
fun getDescription(): String
/**
* Determines what file system paths the tool will affect.
*/
fun getToolLocations(): List
/**
* Executes the tool with the validated parameters.
*/
suspend fun execute(context: ToolExecutionContext = ToolExecutionContext()): TResult
}
/**
* Base implementation of ToolInvocation
*/
abstract class BaseToolInvocation(
override val params: TParams,
override val tool: ExecutableTool
) : ToolInvocation {
override fun getToolLocations(): List = emptyList()
override fun getDescription(): String = "${tool.name} with params: $params"
}
/**
* A tool that can be executed with specific parameters.
* Similar to Gemini CLI's DeclarativeTool concept.
*
* Tools are now self-describing with metadata for UI/TUI display,
* categorization, and schema information.
*/
interface ExecutableTool : Tool {
/**
* Tool metadata including display name, icon, category, and schema
*/
val metadata: ToolMetadata
/**
* Validates parameters and creates a tool invocation
*/
fun createInvocation(params: TParams): ToolInvocation
/**
* Gets the parameter class for this tool
*/
fun getParameterClass(): String
}
abstract class BaseExecutableTool : ExecutableTool {
abstract override val metadata: ToolMetadata
override fun createInvocation(params: TParams): ToolInvocation {
return createToolInvocation(params)
}
protected abstract fun createToolInvocation(params: TParams): ToolInvocation
}