diff --git a/src/uipath_langchain/builder/agent_config.py b/src/uipath_langchain/builder/agent_config.py deleted file mode 100644 index d26237a8..00000000 --- a/src/uipath_langchain/builder/agent_config.py +++ /dev/null @@ -1,191 +0,0 @@ -from enum import Enum -from typing import Annotated, Any, Dict, List, Literal, Optional, Union - -from pydantic import BaseModel, ConfigDict, Field - - -class AgentMessageRole(str, Enum): - """Enum for message roles""" - - SYSTEM = "System" - USER = "User" - - -class AgentMessage(BaseModel): - """Message model for agent conversations""" - - role: AgentMessageRole - content: str - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentSettings(BaseModel): - """Settings for agent configuration""" - - engine: str = Field(..., description="Engine type, e.g., 'basic-v1'") - model: str = Field(..., description="LLM model identifier") - max_tokens: int = Field( - ..., alias="maxTokens", description="Maximum number of tokens" - ) - temperature: float = Field(..., description="Temperature for response generation") - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentResourceType(str, Enum): - """Enum for resource types""" - - TOOL = "tool" - CONTEXT = "context" - ESCALATION = "escalation" - - -class AgentBaseResourceConfig(BaseModel): - """Base resource model with common properties""" - - name: str - description: str - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentUnknownResourceConfig(AgentBaseResourceConfig): - """Fallback for unknown or future resource types""" - - resource_type: str = Field(alias="$resourceType") - - model_config = ConfigDict(extra="allow") - - -class AgentToolSettings(BaseModel): - """Settings for tool configuration""" - - max_attempts: int = Field(0, alias="maxAttempts") - retry_delay: int = Field(0, alias="retryDelay") - timeout: int = Field(0) - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentToolProperties(BaseModel): - """Properties specific to tool configuration""" - - folder_path: Optional[str] = Field(None, alias="folderPath") - process_name: Optional[str] = Field(None, alias="processName") - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentToolResourceConfig(AgentBaseResourceConfig): - """Tool resource with tool-specific properties""" - - resource_type: Literal[AgentResourceType.TOOL] = Field(alias="$resourceType") - type: str = Field(..., description="Tool type") - arguments: Dict[str, Any] = Field( - default_factory=dict, description="Tool arguments" - ) - input_schema: Dict[str, Any] = Field( - ..., alias="inputSchema", description="Input schema for the tool" - ) - output_schema: Dict[str, Any] = Field( - ..., alias="outputSchema", description="Output schema for the tool" - ) - properties: AgentToolProperties = Field(..., description="Tool-specific properties") - settings: AgentToolSettings = Field( - default_factory=AgentToolSettings, description="Tool settings" - ) - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentContextSettings(BaseModel): - """Settings for context configuration""" - - result_count: int = Field(alias="resultCount") - retrieval_mode: Literal["Semantic", "Structured"] = Field(alias="retrievalMode") - threshold: float = Field(default=0) - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentContextResourceConfig(AgentBaseResourceConfig): - """Context resource with context-specific properties""" - - resource_type: Literal[AgentResourceType.CONTEXT] = Field(alias="$resourceType") - folder_path: str = Field(alias="folderPath") - index_name: str = Field(alias="indexName") - settings: AgentContextSettings = Field(..., description="Context settings") - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -class AgentEscalationResourceConfig(AgentBaseResourceConfig): - """Escalation resource with escalation-specific properties""" - - resource_type: Literal[AgentResourceType.ESCALATION] = Field(alias="$resourceType") - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) - - -# Discriminated union for known types -KnownAgentResourceConfig = Annotated[ - Union[ - AgentToolResourceConfig, - AgentContextResourceConfig, - AgentEscalationResourceConfig, - ], - Field(discriminator="resource_type"), -] - -# Final union includes unknowns as a catch-all -AgentResourceConfig = Union[ - KnownAgentResourceConfig, - AgentUnknownResourceConfig, -] - - -class AgentConfig(BaseModel): - """Main agent model""" - - id: str = Field(..., description="Agent id or project name") - name: str = Field(..., description="Agent name or project name") - input_schema: Dict[str, Any] = Field( - ..., alias="inputSchema", description="JSON schema for input arguments" - ) - output_schema: Dict[str, Any] = Field( - ..., alias="outputSchema", description="JSON schema for output arguments" - ) - messages: List[AgentMessage] = Field( - ..., description="List of system and user messages" - ) - features: List[Any] = Field( - default_factory=list, description="Currently empty feature list" - ) - version: str = Field("1.0.0", description="Agent version") - settings: AgentSettings = Field(..., description="Agent settings configuration") - resources: List[AgentResourceConfig] = Field( - ..., description="List of tools, context, and escalation resources" - ) - - model_config = ConfigDict( - validate_by_name=True, validate_by_alias=True, extra="allow" - ) diff --git a/tests/builder/test_config.py b/tests/builder/test_config.py deleted file mode 100644 index 51f3c129..00000000 --- a/tests/builder/test_config.py +++ /dev/null @@ -1,362 +0,0 @@ -from uipath_langchain.builder.agent_config import ( - AgentConfig, - AgentResourceType, - AgentUnknownResourceConfig, -) - - -class TestAgentBuilderConfig: - def test_agent_config_loads_complete_json(self): - """Test that AgentConfig can load from the complete JSON example with all resource types""" - - json_data = { - "features": [], - "id": "0e2201f2-b983-42c6-8231-64806c09ae54", - "inputSchema": { - "properties": {"inputProp": {"type": "string"}}, - "type": "object", - }, - "messages": [ - {"content": "You're a helpful agent.", "role": "System"}, - { - "content": "Use the provided tools. This is the input argument: {{inputProp}}", - "role": "User", - }, - ], - "name": "Agent", - "outputSchema": { - "properties": { - "content": {"description": "Output content", "type": "string"} - }, - "type": "object", - }, - "resources": [ - { - "$resourceType": "escalation", - "channels": [ - { - "description": "Channel description", - "inputSchema": {"properties": {}, "type": "object"}, - "name": "Channel", - "outcomeMapping": {"Submit": "continue"}, - "outputSchema": { - "properties": { - "Content": { - "description": "Text content related to the escalation prompt", - "type": "string", - } - }, - "required": ["Content"], - "type": "object", - }, - "properties": { - "appName": "Untitled", - "appVersion": 1, - "folderName": None, - "resourceKey": "c0aa40e2-9f14-4cea-83f9-c874e229986f", - }, - "recipients": [ - { - "type": "UserId", - "value": "e314e6a1-2499-4ff4-af0b-bb81dc29a6ec", - } - ], - "type": "ActionCenter", - } - ], - "description": '"escalation prompt"', - "id": "2841bace-fa75-4503-9ff0-dff2c1f68750", - "isAgentMemoryEnabled": False, - "name": "Escalation_1", - }, - { - "$resourceType": "tool", - "arguments": {}, - "description": "this is an agent package", - "inputSchema": {"properties": {}, "type": "object"}, - "name": "Agent tool", - "outputSchema": { - "properties": {"output": {"type": "string"}}, - "type": "object", - }, - "properties": { - "folderPath": "Solution Folder", - "processName": "Cristi-Basic-Agent", - }, - "settings": {"maxAttempts": 0, "retryDelay": 0, "timeout": 0}, - "type": "Agent", - }, - { - "$resourceType": "tool", - "arguments": {}, - "description": "Creates an appointment given: first name, second name, personal unique number, doctor specialist, cabinet number, datetime.\nReturns the appointment ID", - "guardrail": { - "policies": [ - { - "action": { - "$actionType": "log", - "severityLevel": "Info", - }, - "description": "test", - "enabledForEvals": True, - "name": "Guardrail_1", - "rules": [ - {"$ruleType": "always", "applyTo": "InputAndOutput"} - ], - } - ] - }, - "inputSchema": { - "properties": { - "cabinet_number": {"type": "integer"}, - "datetime": {"type": "string"}, - "doctor_specialist": {"type": "string"}, - "first_name": {"type": "string"}, - "personal_unique_number": {"type": "string"}, - "second_name": {"type": "string"}, - }, - "required": [], - "type": "object", - }, - "name": "Process tool with a guardrail", - "outputSchema": { - "properties": {"appointment_id": {"type": "integer"}}, - "required": [], - "type": "object", - }, - "properties": { - "folderPath": "Solution Folder", - "processName": "Add_Appointment", - }, - "settings": {"maxAttempts": 0, "retryDelay": 0, "timeout": 0}, - "type": "Process", - }, - { - "$resourceType": "tool", - "arguments": {}, - "description": "Extract readable text from a publicly accessible URL and provide it in a structured format.", - "inputSchema": { - "additionalProperties": False, - "properties": { - "provider": { - "description": "The search engine to use.", - "enum": ["Jina"], - "title": "Search Engine", - "type": "string", - }, - "url": { - "description": "A publicly accessible URL", - "title": "URL", - "type": "string", - }, - }, - "required": ["provider", "url"], - "type": "object", - }, - "name": "IS tool", - "outputSchema": {"properties": {}, "type": "object"}, - "properties": { - "connection": { - "apiBaseUri": "https://alpha.uipath.com/adminstudiotest/cicd/elements_", - "connector": { - "enabled": True, - "image": "https://alpha.uipath.com/elements_/scaleunit_/3854d037-4ab5-4881-909b-968c433f6d88/v3/element/elements/uipath-uipath-airdk/image", - "key": "uipath-uipath-airdk", - "name": "UiPath GenAI Activities", - }, - "elementInstanceId": 180169, - "folder": { - "key": "eb6e6ba2-f2ae-4603-b10d-ab101f0ba91f", - "path": "Agents Test", - }, - "id": "1c5b8b0a-03ed-4cd2-bfe5-9c3a4341443d", - "isDefault": False, - "name": "andrei.neculaesei@uipath.com #2", - "solutionProperties": { - "folder": { - "fullyQualifiedName": "Solution Folder", - "path": "e02827d6-1426-4bfb-13e9-08dd9dd1a5a3", - }, - "resourceKey": "449e43cf-4663-4c44-98c3-5e1a52bd36a3", - }, - "state": "Enabled", - }, - "method": "POST", - "objectName": "v1::webRead", - "parameters": [ - { - "description": "The search engine to use.", - "displayName": "Search Engine", - "dynamic": False, - "dynamicBehavior": [], - "enumValues": [{"name": "Jina", "value": "Jina"}], - "fieldLocation": "body", - "fieldVariant": "static", - "loadReferenceOptionsByDefault": None, - "name": "provider", - "position": "primary", - "reference": None, - "required": True, - "sortOrder": 1, - "type": "string", - "value": "Jina", - }, - { - "description": "A publicly accessible URL", - "displayName": "URL", - "dynamic": True, - "dynamicBehavior": [], - "enumValues": None, - "fieldLocation": "body", - "fieldVariant": "dynamic", - "loadReferenceOptionsByDefault": None, - "name": "url", - "position": "primary", - "reference": None, - "required": True, - "sortOrder": 2, - "type": "string", - }, - ], - "toolDescription": "Extract readable text from a publicly accessible URL and provide it in a structured format.", - "toolDisplayName": "Web Reader", - "toolPath": "/v1/webRead", - }, - "settings": {"maxAttempts": 0, "retryDelay": 0, "timeout": 0}, - "type": "Integration", - }, - { - "$resourceType": "context", - "description": "", - "folderPath": "Solution Folder", - "indexName": "Medical Index", - "name": "Medical Index Semantic", - "settings": { - "resultCount": 3, - "retrievalMode": "Semantic", - "threshold": 0, - }, - }, - { - "$resourceType": "context", - "description": "", - "folderPath": "Solution Folder", - "indexName": "Medical Index", - "name": "Medical Index Structured", - "settings": { - "resultCount": 3, - "retrievalMode": "Structured", - "threshold": 0, - }, - }, - ], - "settings": { - "engine": "basic-v1", - "maxTokens": 16384, - "model": "gpt-4o-2024-11-20", - "temperature": 0, - }, - "version": "1.0.0", - } - - # Test that the model loads without errors - config = AgentConfig(**json_data) - - # Basic assertions - assert config.id == "0e2201f2-b983-42c6-8231-64806c09ae54" - assert config.name == "Agent" - assert config.version == "1.0.0" - assert len(config.messages) == 2 - assert len(config.resources) == 6 # 1 escalation + 3 tools + 2 context - assert config.settings.engine == "basic-v1" - assert config.settings.max_tokens == 16384 - - # Validate resource types - resource_types = [resource.resource_type for resource in config.resources] - assert resource_types.count(AgentResourceType.ESCALATION) == 1 - assert resource_types.count(AgentResourceType.TOOL) == 3 - assert resource_types.count(AgentResourceType.CONTEXT) == 2 - - # Validate specific resources - escalation_resource = next( - r - for r in config.resources - if r.resource_type == AgentResourceType.ESCALATION - ) - assert escalation_resource.name == "Escalation_1" - - tool_resources = [ - r for r in config.resources if r.resource_type == AgentResourceType.TOOL - ] - tool_names = [t.name for t in tool_resources] - assert "Agent tool" in tool_names - assert "Process tool with a guardrail" in tool_names - assert "IS tool" in tool_names - - context_resources = [ - r for r in config.resources if r.resource_type == AgentResourceType.CONTEXT - ] - context_names = [c.name for c in context_resources] - assert "Medical Index Semantic" in context_names - assert "Medical Index Structured" in context_names - - def test_agent_config_loads_unknown_resource_json(self): - """Test that AgentConfig can load JSON with an unknown resource type""" - - json_data = { - "id": "b2564199-e479-4b6f-9336-dc50f457afda", - "version": "1.0.0", - "name": "Agent", - "metadata": { - "storageVersion": "19.0.0", - "isConversational": False, - }, - "messages": [ - {"role": "System", "content": "You are an agentic assistant."}, - {"role": "User", "content": "Search the code..."}, - ], - "inputSchema": {"type": "object", "properties": {}}, - "outputSchema": { - "type": "object", - "properties": { - "content": {"type": "string", "description": "Output content"} - }, - }, - "settings": { - "model": "gpt-4o-2024-11-20", - "maxTokens": 16384, - "temperature": 0, - "engine": "basic-v1", - }, - "resources": [ - { - "$resourceType": "unknownType", - "id": "84250efc-8eb3-471c-8e01-437068dfc464", - "name": "mystery_resource", - "description": "Some new resource we don't know about", - "slug": "mystery-resource", - "folderPath": "Solution Folder", - "extraField": {"foo": "bar"}, - } - ], - } - - config = AgentConfig(**json_data) - - # Basic assertions - assert config.id == "b2564199-e479-4b6f-9336-dc50f457afda" - assert config.name == "Agent" - assert config.version == "1.0.0" - assert config.settings.engine == "basic-v1" - assert config.settings.max_tokens == 16384 - - # Validate resources - assert len(config.resources) == 1 - resource = config.resources[0] - - # Should fall back to AgentUnknownResourceConfig - assert isinstance(resource, AgentUnknownResourceConfig) - assert resource.resource_type == "unknownType" - assert resource.name == "mystery_resource" - assert resource.extraField == {"foo": "bar"} # type: ignore[attr-defined] - assert resource.slug == "mystery-resource" # type: ignore[attr-defined]