kiln_ai.tools
73class KilnTool(KilnToolInterface): 74 """ 75 Base helper class that provides common functionality for tool implementations. 76 Subclasses only need to implement run() and provide tool configuration. 77 """ 78 79 def __init__( 80 self, 81 tool_id: KilnBuiltInToolId, 82 name: str, 83 description: str, 84 parameters_schema: Dict[str, Any], 85 ): 86 self._id = tool_id 87 self._name = name 88 self._description = description 89 validate_schema_dict(parameters_schema) 90 self._parameters_schema = parameters_schema 91 92 async def id(self) -> KilnBuiltInToolId: 93 return self._id 94 95 async def name(self) -> str: 96 return self._name 97 98 async def description(self) -> str: 99 return self._description 100 101 async def toolcall_definition(self) -> ToolCallDefinition: 102 """Generate OpenAI-compatible tool definition.""" 103 return { 104 "type": "function", 105 "function": { 106 "name": await self.name(), 107 "description": await self.description(), 108 "parameters": self._parameters_schema, 109 }, 110 } 111 112 @abstractmethod 113 async def run( 114 self, context: ToolCallContext | None = None, **kwargs 115 ) -> ToolCallResult: 116 """Subclasses must implement the actual tool logic.""" 117 pass
Base helper class that provides common functionality for tool implementations. Subclasses only need to implement run() and provide tool configuration.
async def
id(self) -> kiln_ai.datamodel.tool_id.KilnBuiltInToolId:
Return a unique identifier for this tool.
async def
toolcall_definition(self) -> kiln_ai.tools.base_tool.ToolCallDefinition:
101 async def toolcall_definition(self) -> ToolCallDefinition: 102 """Generate OpenAI-compatible tool definition.""" 103 return { 104 "type": "function", 105 "function": { 106 "name": await self.name(), 107 "description": await self.description(), 108 "parameters": self._parameters_schema, 109 }, 110 }
Generate OpenAI-compatible tool definition.
@abstractmethod
async def
run( self, context: kiln_ai.tools.base_tool.ToolCallContext | None = None, **kwargs) -> kiln_ai.tools.base_tool.ToolCallResult:
112 @abstractmethod 113 async def run( 114 self, context: ToolCallContext | None = None, **kwargs 115 ) -> ToolCallResult: 116 """Subclasses must implement the actual tool logic.""" 117 pass
Subclasses must implement the actual tool logic.
class
KilnToolInterface(abc.ABC):
39class KilnToolInterface(ABC): 40 """ 41 Abstract interface defining the core API that all Kiln tools must implement. 42 This ensures consistency across all tool implementations. 43 """ 44 45 @abstractmethod 46 async def run( 47 self, context: ToolCallContext | None = None, **kwargs 48 ) -> ToolCallResult: 49 """Execute the tool with the given parameters and calling context if provided.""" 50 pass 51 52 @abstractmethod 53 async def toolcall_definition(self) -> ToolCallDefinition: 54 """Return the OpenAI-compatible tool definition for this tool.""" 55 pass 56 57 @abstractmethod 58 async def id(self) -> ToolId: 59 """Return a unique identifier for this tool.""" 60 pass 61 62 @abstractmethod 63 async def name(self) -> str: 64 """Return the tool name (function name) of this tool.""" 65 pass 66 67 @abstractmethod 68 async def description(self) -> str: 69 """Return a description of what this tool does.""" 70 pass
Abstract interface defining the core API that all Kiln tools must implement. This ensures consistency across all tool implementations.
@abstractmethod
async def
run( self, context: kiln_ai.tools.base_tool.ToolCallContext | None = None, **kwargs) -> kiln_ai.tools.base_tool.ToolCallResult:
45 @abstractmethod 46 async def run( 47 self, context: ToolCallContext | None = None, **kwargs 48 ) -> ToolCallResult: 49 """Execute the tool with the given parameters and calling context if provided.""" 50 pass
Execute the tool with the given parameters and calling context if provided.
@abstractmethod
async def
toolcall_definition(self) -> kiln_ai.tools.base_tool.ToolCallDefinition:
52 @abstractmethod 53 async def toolcall_definition(self) -> ToolCallDefinition: 54 """Return the OpenAI-compatible tool definition for this tool.""" 55 pass
Return the OpenAI-compatible tool definition for this tool.
@abstractmethod
async def
id( self) -> Annotated[str, AfterValidator(func=<function <lambda> at 0x7f1944608860>)]:
57 @abstractmethod 58 async def id(self) -> ToolId: 59 """Return a unique identifier for this tool.""" 60 pass
Return a unique identifier for this tool.
26def tool_from_id(tool_id: str, task: Task | None = None) -> KilnToolInterface: 27 """ 28 Get a tool from its ID. 29 """ 30 # Check built-in tools 31 if tool_id in [member.value for member in KilnBuiltInToolId]: 32 typed_tool_id = KilnBuiltInToolId(tool_id) 33 match typed_tool_id: 34 case KilnBuiltInToolId.ADD_NUMBERS: 35 return AddTool() 36 case KilnBuiltInToolId.SUBTRACT_NUMBERS: 37 return SubtractTool() 38 case KilnBuiltInToolId.MULTIPLY_NUMBERS: 39 return MultiplyTool() 40 case KilnBuiltInToolId.DIVIDE_NUMBERS: 41 return DivideTool() 42 case _: 43 raise_exhaustive_enum_error(typed_tool_id) 44 45 # Check if this looks like an MCP or Kiln Task tool ID that requires a project 46 is_mcp_tool = tool_id.startswith( 47 (MCP_REMOTE_TOOL_ID_PREFIX, MCP_LOCAL_TOOL_ID_PREFIX) 48 ) 49 is_kiln_task_tool = tool_id.startswith(KILN_TASK_TOOL_ID_PREFIX) 50 51 if is_mcp_tool or is_kiln_task_tool: 52 project = task.parent_project() if task is not None else None 53 if project is None or project.id is None: 54 raise ValueError( 55 f"Unable to resolve tool from id: {tool_id}. Requires a parent project/task." 56 ) 57 58 # Check MCP Server Tools 59 if is_mcp_tool: 60 # Get the tool server ID and tool name from the ID 61 tool_server_id, tool_name = mcp_server_and_tool_name_from_id( 62 tool_id 63 ) # Fixed function name 64 65 server = next( 66 ( 67 server 68 for server in project.external_tool_servers() 69 if server.id == tool_server_id 70 ), 71 None, 72 ) 73 if server is None: 74 raise ValueError( 75 f"External tool server not found: {tool_server_id} in project ID {project.id}" 76 ) 77 78 return MCPServerTool(server, tool_name) 79 80 # Check Kiln Task Tools 81 if is_kiln_task_tool: 82 server_id = kiln_task_server_id_from_tool_id(tool_id) 83 84 server = next( 85 ( 86 server 87 for server in project.external_tool_servers() 88 if server.id == server_id 89 ), 90 None, 91 ) 92 if server is None: 93 raise ValueError( 94 f"Kiln Task External tool server not found: {server_id} in project ID {project.id}" 95 ) 96 97 return KilnTaskTool(project.id, tool_id, server) 98 99 elif tool_id.startswith(RAG_TOOL_ID_PREFIX): 100 project = task.parent_project() if task is not None else None 101 if project is None: 102 raise ValueError( 103 f"Unable to resolve tool from id: {tool_id}. Requires a parent project/task." 104 ) 105 106 rag_config_id = rag_config_id_from_id(tool_id) 107 rag_config = RagConfig.from_id_and_parent_path(rag_config_id, project.path) 108 if rag_config is None: 109 raise ValueError( 110 f"RAG config not found: {rag_config_id} in project {project.id} for tool {tool_id}" 111 ) 112 113 # Lazy import to avoid circular dependency 114 from kiln_ai.tools.rag_tools import RagTool 115 116 return RagTool(tool_id, rag_config) 117 118 raise ValueError(f"Tool ID {tool_id} not found in tool registry")
Get a tool from its ID.