hivetrace 1.3.15__py3-none-any.whl → 1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@ class ValidationError(HiveTraceError):
14
14
  class InvalidParameterError(ValidationError):
15
15
  """Exception for invalid parameter."""
16
16
 
17
- def __init__(self, parameter: str, message: str = None):
17
+ def __init__(self, parameter: str, message: str | None = None):
18
18
  message = message or f"Invalid parameter: {parameter}"
19
19
  super().__init__(message)
20
20
  self.parameter = parameter
@@ -1,7 +1,6 @@
1
- from datetime import datetime
2
1
  from typing import Any, Dict, Optional
3
2
 
4
- from ..models.responses import HivetraceResponse, ProcessResponse, SuccessResponse
3
+ from ..models.responses import HivetraceResponse, ProcessResponse
5
4
 
6
5
 
7
6
  class ResponseBuilder:
@@ -9,81 +8,29 @@ class ResponseBuilder:
9
8
  Response builder for creating structured responses.
10
9
  """
11
10
 
12
- @staticmethod
13
- def build_success_response(
14
- data: Dict[str, Any] = None, request_id: Optional[str] = None
15
- ) -> SuccessResponse:
16
- """Builds a successful response."""
17
- return SuccessResponse(
18
- success=True,
19
- timestamp=datetime.utcnow().isoformat(),
20
- request_id=request_id,
21
- **(data or {}),
22
- )
23
-
24
11
  @staticmethod
25
12
  def build_process_response(
26
- message_id: Optional[str] = None,
27
- trace_id: Optional[str] = None,
28
- request_id: Optional[str] = None,
29
- additional_data: Dict[str, Any] = None,
13
+ data: Optional[Dict[str, Any]] = None,
30
14
  ) -> ProcessResponse:
31
- """Builds a response to process a message."""
32
- return ProcessResponse(
33
- success=True,
34
- timestamp=datetime.utcnow().isoformat(),
35
- message_id=message_id,
36
- trace_id=trace_id,
37
- request_id=request_id,
38
- **(additional_data or {}),
39
- )
15
+ """Builds a process response directly from API payload."""
16
+ return ProcessResponse(**(data or {}))
40
17
 
41
18
  @staticmethod
42
19
  def build_response_from_api(
43
- api_response: Dict[str, Any], request_id: Optional[str] = None
20
+ api_response: Dict[str, Any],
21
+ request_id: Optional[str] = None,
22
+ *,
23
+ endpoint: Optional[str] = None,
44
24
  ) -> HivetraceResponse:
45
25
  """
46
- Builds a response from API data.
26
+ Builds a typed response from API data when appropriate.
47
27
 
48
- Automatically determines the response type and creates the corresponding model.
28
+ We keep the SDK "transparent" by only parsing into `ProcessResponse` for
29
+ `/process_*` endpoints. For other endpoints we return the raw dict, since
30
+ their payload shapes can vary.
49
31
  """
50
- excluded_keys = {
51
- "message_id",
52
- "trace_id",
53
- "request_id",
54
- "success",
55
- "timestamp",
56
- "blocked",
57
- }
58
32
 
59
- if (
60
- api_response.get("success")
61
- or "message_id" in api_response
62
- or "trace_id" in api_response
63
- ):
64
- return ResponseBuilder.build_process_response(
65
- message_id=api_response.get("message_id"),
66
- trace_id=api_response.get("trace_id"),
67
- request_id=api_response.get("request_id", request_id),
68
- additional_data={
69
- k: v
70
- for k, v in api_response.items()
71
- if k not in excluded_keys
72
- },
73
- )
33
+ if endpoint and endpoint.startswith("/process_"):
34
+ return ResponseBuilder.build_process_response(api_response)
74
35
 
75
36
  return api_response
76
-
77
- @staticmethod
78
- def add_request_id(
79
- response: HivetraceResponse, request_id: str
80
- ) -> HivetraceResponse:
81
- """Adds request_id to an existing response."""
82
- if isinstance(response, dict):
83
- response["request_id"] = request_id
84
- return response
85
- elif hasattr(response, "request_id"):
86
- response.request_id = request_id
87
- return response
88
- else:
89
- return response
@@ -1,15 +1,23 @@
1
1
  from typing import Any, Dict, Optional, Union
2
2
  from uuid import UUID
3
3
 
4
- from pydantic import BaseModel, Field, validator
4
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
5
5
 
6
6
 
7
7
  class BaseRequest(BaseModel):
8
8
  """Base request model."""
9
9
 
10
- class Config:
11
- extra = "forbid"
12
- use_enum_values = True
10
+ model_config = ConfigDict(extra="forbid", use_enum_values=True)
11
+
12
+ @field_validator("application_id", check_fields=False)
13
+ @classmethod
14
+ def validate_application_id(cls, v: str) -> str:
15
+ """Validation of UUID."""
16
+ try:
17
+ UUID(v)
18
+ return v
19
+ except ValueError:
20
+ raise ValueError("application_id must be a valid UUID")
13
21
 
14
22
 
15
23
  class MessageRequest(BaseRequest):
@@ -21,17 +29,9 @@ class MessageRequest(BaseRequest):
21
29
  None, description="Additional parameters"
22
30
  )
23
31
 
24
- @validator("application_id")
25
- def validate_application_id(cls, v):
26
- """Validation of UUID."""
27
- try:
28
- UUID(v)
29
- return v
30
- except ValueError:
31
- raise ValueError("application_id must be a valid UUID")
32
-
33
- @validator("message")
34
- def validate_message(cls, v):
32
+ @field_validator("message")
33
+ @classmethod
34
+ def validate_message(cls, v: str) -> str:
35
35
  """Validation of message."""
36
36
  if not v.strip():
37
37
  raise ValueError("Message cannot be empty")
@@ -64,24 +64,17 @@ class FunctionCallRequest(BaseRequest):
64
64
  None, description="Additional parameters"
65
65
  )
66
66
 
67
- @validator("application_id")
68
- def validate_application_id(cls, v):
69
- """Validation of UUID."""
70
- try:
71
- UUID(v)
72
- return v
73
- except ValueError:
74
- raise ValueError("application_id must be a valid UUID")
75
-
76
- @validator("func_name")
77
- def validate_func_name(cls, v):
67
+ @field_validator("func_name")
68
+ @classmethod
69
+ def validate_func_name(cls, v: str) -> str:
78
70
  """Validation of function name."""
79
71
  if not v.strip():
80
72
  raise ValueError("Function name cannot be empty")
81
73
  return v.strip()
82
74
 
83
- @validator("tool_call_id")
84
- def validate_tool_call_id(cls, v):
75
+ @field_validator("tool_call_id")
76
+ @classmethod
77
+ def validate_tool_call_id(cls, v: str) -> str:
85
78
  """Validation of tool call ID."""
86
79
  if not v.strip():
87
80
  raise ValueError("Tool call ID cannot be empty")
@@ -1,44 +1,49 @@
1
1
  from typing import Any, Dict, List, Literal, Optional, Union
2
2
 
3
- from pydantic import BaseModel, Field
3
+ from pydantic import BaseModel, ConfigDict, Field
4
4
 
5
5
 
6
6
  class BaseResponse(BaseModel):
7
7
  """Base response model."""
8
8
 
9
- class Config:
10
- extra = "allow"
11
- use_enum_values = True
9
+ model_config = ConfigDict(extra="allow", use_enum_values=True)
12
10
 
13
11
 
14
12
  class SuccessResponse(BaseResponse):
15
13
  """Success response from HiveTrace API."""
16
14
 
17
- success: bool = Field(True, description="Success flag")
18
- timestamp: Optional[str] = Field(None, description="Timestamp")
19
- request_id: Optional[str] = Field(None, description="Request ID for tracking")
20
-
21
-
22
- class ProcessResponse(SuccessResponse):
23
- """Response to process a message."""
24
-
25
- message_id: Optional[str] = Field(None, description="ID of processed message")
26
- trace_id: Optional[str] = Field(None, description="Trace ID")
27
- blocked: Optional[bool] = Field(
28
- None,
29
- description="Role restriction flag. True if message/response is blocked by policy.",
15
+ success: bool = Field(default=True, description="Success flag")
16
+ timestamp: Optional[str] = Field(default=None, description="Timestamp")
17
+ request_id: Optional[str] = Field(default=None, description="Request ID for tracking")
18
+
19
+
20
+ class ProcessResponse(BaseResponse):
21
+ """
22
+ Response model for `/process_request/` and `/process_response/`.
23
+ Matches the API payload shape (no SDK-added fields).
24
+ """
25
+
26
+ request_id: Optional[str] = Field(default=None, description="Request ID for tracking")
27
+ schema_version: Optional[str] = Field(default=None, description="Schema version")
28
+ status: Optional[str] = Field(default=None, description="Status string")
29
+ errors: List[Any] = Field(default_factory=list, description="Errors list")
30
+ tokens: Optional[Dict[str, Any]] = Field(default=None, description="Token usage info")
31
+ guardrails: Optional[Dict[str, Any]] = Field(default=None, description="Guardrails result")
32
+ custom_policy: Optional[Dict[str, Any]] = Field(
33
+ default=None, description="Custom policy result"
30
34
  )
35
+ dataclean: Optional[Dict[str, Any]] = Field(default=None, description="Data cleaning result")
31
36
 
32
37
 
33
38
  class ErrorResponse(BaseResponse):
34
39
  """Base response model with error."""
35
40
 
36
- success: bool = Field(False, description="Success flag")
41
+ success: bool = Field(default=False, description="Success flag")
37
42
  error: str = Field(..., description="Error message")
38
43
  error_type: str = Field(..., description="Error type")
39
44
  details: str = Field(..., description="Error details")
40
- status_code: Optional[int] = Field(None, description="HTTP status code")
41
- request_id: Optional[str] = Field(None, description="Request ID for tracking")
45
+ status_code: Optional[int] = Field(default=None, description="HTTP status code")
46
+ request_id: Optional[str] = Field(default=None, description="Request ID for tracking")
42
47
 
43
48
 
44
49
  class ConnectionErrorResponse(ErrorResponse):
@@ -81,7 +86,7 @@ class ValidationErrorResponse(ErrorResponse):
81
86
 
82
87
  error_type: Literal["validation_error"] = "validation_error"
83
88
  field_errors: Optional[List[Dict[str, Any]]] = Field(
84
- None, description="Field validation errors"
89
+ default=None, description="Field validation errors"
85
90
  )
86
91
 
87
92
 
@@ -10,8 +10,19 @@ from ..models.responses import HivetraceResponse
10
10
  def is_error_response(response: HivetraceResponse) -> bool:
11
11
  """Checks if the response is an error."""
12
12
  if isinstance(response, dict):
13
- return "error" in response
14
- return hasattr(response, "error") and hasattr(response, "error_type")
13
+ if response.get("error") or response.get("error_type"):
14
+ return True
15
+ status = response.get("status")
16
+ if isinstance(status, str) and "success" not in status.lower():
17
+ return True
18
+ return False
19
+
20
+ if getattr(response, "error", None) or getattr(response, "error_type", None):
21
+ return True
22
+ status = getattr(response, "status", None)
23
+ if isinstance(status, str) and "success" not in status.lower():
24
+ return True
25
+ return False
15
26
 
16
27
 
17
28
  def get_error_type(response: HivetraceResponse) -> Optional[str]:
@@ -74,5 +85,16 @@ def get_status_code(response: HivetraceResponse) -> Optional[int]:
74
85
  def is_success_response(response: HivetraceResponse) -> bool:
75
86
  """Checks if the response is a success."""
76
87
  if isinstance(response, dict):
88
+ status = response.get("status")
89
+ if isinstance(status, str):
90
+ return "success" in status.lower() and "error" not in response
77
91
  return response.get("success", True) and "error" not in response
78
- return hasattr(response, "success") and getattr(response, "success", True)
92
+
93
+ if hasattr(response, "success"):
94
+ return bool(getattr(response, "success", True))
95
+
96
+ status = getattr(response, "status", None)
97
+ if isinstance(status, str):
98
+ return "success" in status.lower()
99
+
100
+ return False