11import inspect
22import logging
33import types
4- from typing import Any , Dict , Optional , Union , Callable
4+ from pathlib import Path
5+ from typing import Any , Callable , Dict , Optional , Union
56
7+ from humanloop import path_utils
8+ from humanloop .agents .client import AgentsClient
69from humanloop .context import (
710 get_decorator_context ,
811 get_evaluation_context ,
912 get_trace_id ,
1013)
14+ from humanloop .datasets .client import DatasetsClient
1115from humanloop .error import HumanloopRuntimeError
12- from humanloop .sync .sync_client import SyncClient
13- from humanloop .prompts .client import PromptsClient
16+ from humanloop .evaluators .client import EvaluatorsClient
1417from humanloop .flows .client import FlowsClient
15- from humanloop .datasets .client import DatasetsClient
16- from humanloop .agents . client import AgentsClient
18+ from humanloop .prompts .client import PromptsClient
19+ from humanloop .sync . sync_client import SyncClient
1720from humanloop .tools .client import ToolsClient
18- from humanloop .evaluators .client import EvaluatorsClient
1921from humanloop .types import FileType
22+ from humanloop .types .agent_call_response import AgentCallResponse
2023from humanloop .types .create_evaluator_log_response import CreateEvaluatorLogResponse
2124from humanloop .types .create_flow_log_response import CreateFlowLogResponse
2225from humanloop .types .create_prompt_log_response import CreatePromptLogResponse
2326from humanloop .types .create_tool_log_response import CreateToolLogResponse
2427from humanloop .types .prompt_call_response import PromptCallResponse
25- from humanloop .types .agent_call_response import AgentCallResponse
2628
2729logger = logging .getLogger ("humanloop.sdk" )
2830
@@ -95,16 +97,21 @@ def _handle_local_files(
9597
9698 path = kwargs ["path" ]
9799
98- # Check if the path has a file type extension (.prompt/.agent)
99- if sync_client .is_file (path ):
100- file_type = _get_file_type_from_client (client )
100+ # First check for path format issues (absolute paths or leading/trailing slashes)
101+ normalized_path = path .strip ("/" )
102+ if Path (path ).is_absolute () or path != normalized_path :
103+ raise HumanloopRuntimeError (
104+ f"Path '{ path } ' format is invalid. "
105+ f"Paths must follow the standard API format 'path/to/resource' without leading or trailing slashes. "
106+ f"Please use '{ normalized_path } ' instead."
107+ )
101108
102- # Safely extract the extension and path by handling potential errors
109+ # Then check for file extensions
110+ if sync_client .is_file (path ):
103111 try :
104112 parts = path .rsplit ("." , 1 )
105113 path_without_extension = parts [0 ] if len (parts ) > 0 else path
106114 except Exception :
107- # Fallback to original path if any error occurs
108115 path_without_extension = path
109116
110117 raise HumanloopRuntimeError (
@@ -124,7 +131,7 @@ def _handle_local_files(
124131
125132 file_type = _get_file_type_from_client (client )
126133 if file_type not in SyncClient .SERIALIZABLE_FILE_TYPES :
127- raise HumanloopRuntimeError (f"Local files are not supported for `{ file_type } ` files." )
134+ raise HumanloopRuntimeError (f"Local files are not supported for `{ file_type . capitalize () } ` files: ' { path } ' ." )
128135
129136 # If file_type is already specified in kwargs (prompt or agent), it means user provided a Prompt- or AgentKernelRequestParams object
130137 if file_type in kwargs and not isinstance (kwargs [file_type ], str ):
0 commit comments