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 0x7f5e59a694e0>)]:
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 = is_mcp_tool_id(tool_id) 47 is_kiln_task_tool = tool_id.startswith(KILN_TASK_TOOL_ID_PREFIX) 48 49 if is_mcp_tool or is_kiln_task_tool: 50 project = task.parent_project() if task is not None else None 51 if project is None or project.id is None: 52 raise ValueError( 53 f"Unable to resolve tool from id: {tool_id}. Requires a parent project/task." 54 ) 55 56 # Check MCP Server Tools 57 if is_mcp_tool: 58 # Get the tool server ID and tool name from the ID 59 tool_server_id, tool_name = mcp_server_and_tool_name_from_id( 60 tool_id 61 ) # Fixed function name 62 63 server = next( 64 ( 65 server 66 for server in project.external_tool_servers() 67 if server.id == tool_server_id 68 ), 69 None, 70 ) 71 if server is None: 72 raise ValueError( 73 f"External tool server not found: {tool_server_id} in project ID {project.id}" 74 ) 75 76 return MCPServerTool(server, tool_name) 77 78 # Check Kiln Task Tools 79 if is_kiln_task_tool: 80 server_id = kiln_task_server_id_from_tool_id(tool_id) 81 82 server = next( 83 ( 84 server 85 for server in project.external_tool_servers() 86 if server.id == server_id 87 ), 88 None, 89 ) 90 if server is None: 91 raise ValueError( 92 f"Kiln Task External tool server not found: {server_id} in project ID {project.id}" 93 ) 94 95 return KilnTaskTool(project.id, tool_id, server) 96 97 elif tool_id.startswith(RAG_TOOL_ID_PREFIX): 98 project = task.parent_project() if task is not None else None 99 if project is None: 100 raise ValueError( 101 f"Unable to resolve tool from id: {tool_id}. Requires a parent project/task." 102 ) 103 104 rag_config_id = rag_config_id_from_id(tool_id) 105 rag_config = RagConfig.from_id_and_parent_path(rag_config_id, project.path) 106 if rag_config is None: 107 raise ValueError( 108 f"RAG config not found: {rag_config_id} in project {project.id} for tool {tool_id}" 109 ) 110 111 # Lazy import to avoid circular dependency 112 from kiln_ai.tools.rag_tools import RagTool 113 114 return RagTool(tool_id, rag_config) 115 116 raise ValueError(f"Tool ID {tool_id} not found in tool registry")
Get a tool from its ID.