arthur-common 2.1.59__py3-none-any.whl → 2.1.61__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.

Potentially problematic release.


This version of arthur-common might be problematic. Click here for more details.

@@ -172,7 +172,9 @@ class SketchAggregationFunction(AggregationFunction, ABC):
172
172
  groups = data.groupby(dim_columns, dropna=False)
173
173
  for _, group in groups:
174
174
  calculated_metrics.append(
175
- SketchAggregationFunction._group_to_series(group, timestamp_col, dim_columns, value_col),
175
+ SketchAggregationFunction._group_to_series(
176
+ group, timestamp_col, dim_columns, value_col
177
+ ),
176
178
  )
177
179
 
178
180
  return calculated_metrics
@@ -10,7 +10,7 @@ from arthur_common.aggregations.aggregator import (
10
10
  NumericAggregationFunction,
11
11
  SketchAggregationFunction,
12
12
  )
13
- from arthur_common.models.datasets import ModelProblemType
13
+ from arthur_common.models.enums import ModelProblemType
14
14
  from arthur_common.models.metrics import (
15
15
  BaseReportedAggregation,
16
16
  DatasetReference,
@@ -4,7 +4,7 @@ from uuid import UUID
4
4
  from duckdb import DuckDBPyConnection
5
5
 
6
6
  from arthur_common.aggregations.aggregator import NumericAggregationFunction
7
- from arthur_common.models.datasets import ModelProblemType
7
+ from arthur_common.models.enums import ModelProblemType
8
8
  from arthur_common.models.metrics import (
9
9
  BaseReportedAggregation,
10
10
  DatasetReference,
@@ -4,7 +4,7 @@ from uuid import UUID
4
4
  from duckdb import DuckDBPyConnection
5
5
 
6
6
  from arthur_common.aggregations.aggregator import NumericAggregationFunction
7
- from arthur_common.models.datasets import ModelProblemType
7
+ from arthur_common.models.enums import ModelProblemType
8
8
  from arthur_common.models.metrics import (
9
9
  BaseReportedAggregation,
10
10
  DatasetReference,
@@ -4,7 +4,7 @@ from uuid import UUID
4
4
  from duckdb import DuckDBPyConnection
5
5
 
6
6
  from arthur_common.aggregations.aggregator import NumericAggregationFunction
7
- from arthur_common.models.datasets import ModelProblemType
7
+ from arthur_common.models.enums import ModelProblemType
8
8
  from arthur_common.models.metrics import (
9
9
  BaseReportedAggregation,
10
10
  DatasetReference,
@@ -4,7 +4,7 @@ from uuid import UUID
4
4
  from duckdb import DuckDBPyConnection
5
5
 
6
6
  from arthur_common.aggregations.aggregator import NumericAggregationFunction
7
- from arthur_common.models.datasets import ModelProblemType
7
+ from arthur_common.models.enums import ModelProblemType
8
8
  from arthur_common.models.metrics import (
9
9
  BaseReportedAggregation,
10
10
  DatasetReference,
@@ -4,7 +4,7 @@ from uuid import UUID
4
4
  from duckdb import DuckDBPyConnection
5
5
 
6
6
  from arthur_common.aggregations.aggregator import NumericAggregationFunction
7
- from arthur_common.models.datasets import ModelProblemType
7
+ from arthur_common.models.enums import ModelProblemType
8
8
  from arthur_common.models.metrics import (
9
9
  BaseReportedAggregation,
10
10
  DatasetReference,
@@ -6,7 +6,7 @@ from duckdb import DuckDBPyConnection
6
6
  from arthur_common.aggregations.functions.inference_count_by_class import (
7
7
  BinaryClassifierCountByClassAggregationFunction,
8
8
  )
9
- from arthur_common.models.datasets import ModelProblemType
9
+ from arthur_common.models.enums import ModelProblemType
10
10
  from arthur_common.models.metrics import (
11
11
  BaseReportedAggregation,
12
12
  DatasetReference,
@@ -9,7 +9,7 @@ from arthur_common.aggregations.aggregator import (
9
9
  NumericAggregationFunction,
10
10
  SketchAggregationFunction,
11
11
  )
12
- from arthur_common.models.datasets import ModelProblemType
12
+ from arthur_common.models.enums import ModelProblemType
13
13
  from arthur_common.models.metrics import (
14
14
  BaseReportedAggregation,
15
15
  DatasetReference,
@@ -0,0 +1,208 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
6
+
7
+ from arthur_common.models.constants import (
8
+ DEFAULT_PII_RULE_CONFIDENCE_SCORE_THRESHOLD,
9
+ DEFAULT_TOXICITY_RULE_THRESHOLD,
10
+ NEGATIVE_BLOOD_EXAMPLE,
11
+ )
12
+ from arthur_common.models.enums import (
13
+ PaginationSortMethod,
14
+ PIIEntityTypes,
15
+ UserPermissionAction,
16
+ UserPermissionResource,
17
+ )
18
+
19
+
20
+ class AuthUserRole(BaseModel):
21
+ id: str | None = None
22
+ name: str
23
+ description: str
24
+ composite: bool
25
+
26
+
27
+ class ExampleConfig(BaseModel):
28
+ example: str = Field(description="Custom example for the sensitive data")
29
+ result: bool = Field(
30
+ description="Boolean value representing if the example passes or fails the the sensitive "
31
+ "data rule ",
32
+ )
33
+
34
+ model_config = ConfigDict(
35
+ json_schema_extra={
36
+ "example": {"example": NEGATIVE_BLOOD_EXAMPLE, "result": True},
37
+ },
38
+ )
39
+
40
+
41
+ class ExamplesConfig(BaseModel):
42
+ examples: List[ExampleConfig] = Field(
43
+ description="List of all the examples for Sensitive Data Rule",
44
+ )
45
+
46
+ model_config = ConfigDict(
47
+ json_schema_extra={
48
+ "example": {
49
+ "examples": [
50
+ {"example": NEGATIVE_BLOOD_EXAMPLE, "result": True},
51
+ {
52
+ "example": "Most of the people have A positive blood group",
53
+ "result": False,
54
+ },
55
+ ],
56
+ "hint": "specific individual's blood type",
57
+ },
58
+ },
59
+ )
60
+ hint: Optional[str] = Field(
61
+ description="Optional. Hint added to describe what Sensitive Data Rule should be checking for",
62
+ default=None,
63
+ )
64
+
65
+ def to_dict(self) -> Dict[str, Any]:
66
+ d = self.__dict__
67
+ d["examples"] = [ex.__dict__ for ex in self.examples]
68
+ d["hint"] = self.hint
69
+ return d
70
+
71
+
72
+ class KeywordsConfig(BaseModel):
73
+ keywords: List[str] = Field(description="List of Keywords")
74
+
75
+ model_config = ConfigDict(
76
+ json_schema_extra={
77
+ "example": {"keywords": ["Blocked_Keyword_1", "Blocked_Keyword_2"]},
78
+ },
79
+ )
80
+
81
+
82
+ class LLMTokenConsumption(BaseModel):
83
+ prompt_tokens: int
84
+ completion_tokens: int
85
+
86
+ def total_tokens(self) -> int:
87
+ return self.prompt_tokens + self.completion_tokens
88
+
89
+ def add(self, token_consumption: LLMTokenConsumption) -> "LLMTokenConsumption":
90
+ self.prompt_tokens += token_consumption.prompt_tokens
91
+ self.completion_tokens += token_consumption.completion_tokens
92
+ return self
93
+
94
+
95
+ class PaginationParameters(BaseModel):
96
+ sort: Optional[PaginationSortMethod] = PaginationSortMethod.DESCENDING
97
+ page_size: int = 10
98
+ page: int = 0
99
+
100
+ def calculate_total_pages(self, total_items_count: int) -> int:
101
+ return total_items_count // self.page_size + 1
102
+
103
+
104
+ class PIIConfig(BaseModel):
105
+ disabled_pii_entities: Optional[list[str]] = Field(
106
+ description=f"Optional. List of PII entities to disable. Valid values are: {PIIEntityTypes.to_string()}",
107
+ default=None,
108
+ )
109
+
110
+ confidence_threshold: Optional[float] = Field(
111
+ description=f"Optional. Float (0, 1) indicating the level of tolerable PII to consider the rule passed or failed. Min: 0 (less confident) Max: 1 (very confident). Default: {DEFAULT_PII_RULE_CONFIDENCE_SCORE_THRESHOLD}",
112
+ default=DEFAULT_PII_RULE_CONFIDENCE_SCORE_THRESHOLD,
113
+ json_schema_extra={"deprecated": True},
114
+ )
115
+
116
+ allow_list: Optional[list[str]] = Field(
117
+ description="Optional. List of strings to pass PII validation.",
118
+ default=None,
119
+ )
120
+
121
+ @field_validator("disabled_pii_entities")
122
+ def validate_pii_entities(cls, v: list[str] | None) -> list[str] | None:
123
+ if v:
124
+ entities_passed = set(v)
125
+ entities_supported = set(PIIEntityTypes.values())
126
+ invalid_entities = entities_passed - entities_supported
127
+ if invalid_entities:
128
+ raise ValueError(
129
+ f"The following values are not valid PII entities: {invalid_entities}",
130
+ )
131
+
132
+ # Fail the case where they are trying to disable all PII entity types
133
+ if (not invalid_entities) & (
134
+ len(entities_passed) == len(entities_supported)
135
+ ):
136
+ raise ValueError(
137
+ f"Cannot disable all supported PII entities on PIIDataRule",
138
+ )
139
+ return v
140
+ else:
141
+ return v
142
+
143
+ @field_validator("confidence_threshold")
144
+ def validate_confidence_threshold(cls, v: float | None) -> float | None:
145
+ if v:
146
+ if (v < 0) | (v > 1):
147
+ raise ValueError(f'"confidence_threshold" must be between 0 and 1')
148
+ return v
149
+ else:
150
+ return v
151
+
152
+ model_config = ConfigDict(
153
+ json_schema_extra={
154
+ "example": {
155
+ "disabled_pii_entities": ["PERSON", "URL"],
156
+ "confidence_threshold": "0.5",
157
+ "allow_list": ["arthur.ai", "Arthur"],
158
+ },
159
+ },
160
+ extra="forbid",
161
+ )
162
+
163
+
164
+ class RegexConfig(BaseModel):
165
+ regex_patterns: List[str] = Field(
166
+ description="List of Regex patterns to be used for validation. Be sure to encode requests in JSON and account for escape characters.",
167
+ )
168
+
169
+ model_config = ConfigDict(
170
+ json_schema_extra={
171
+ "example": {
172
+ "regex_patterns": ["\\d{3}-\\d{2}-\\d{4}", "\\d{5}-\\d{6}-\\d{7}"],
173
+ },
174
+ },
175
+ extra="forbid",
176
+ )
177
+
178
+
179
+ class ToxicityConfig(BaseModel):
180
+ threshold: float = Field(
181
+ default=DEFAULT_TOXICITY_RULE_THRESHOLD,
182
+ description=f"Optional. Float (0, 1) indicating the level of tolerable toxicity to consider the rule passed or failed. Min: 0 (no toxic language) Max: 1 (very toxic language). Default: {DEFAULT_TOXICITY_RULE_THRESHOLD}",
183
+ )
184
+
185
+ model_config = ConfigDict(
186
+ extra="forbid",
187
+ json_schema_extra={"example": {"threshold": DEFAULT_TOXICITY_RULE_THRESHOLD}},
188
+ )
189
+
190
+ @field_validator("threshold", mode="before")
191
+ @classmethod
192
+ def validate_toxicity_threshold(cls, v: float | None) -> float:
193
+ if v is None:
194
+ return float(DEFAULT_TOXICITY_RULE_THRESHOLD)
195
+ if (v < 0) | (v > 1):
196
+ raise ValueError(f'"threshold" must be between 0 and 1')
197
+ return v
198
+
199
+
200
+ class UserPermission(BaseModel):
201
+ action: UserPermissionAction
202
+ resource: UserPermissionResource
203
+
204
+ def __hash__(self) -> int:
205
+ return hash((self.action, self.resource))
206
+
207
+ def __eq__(self, other: object) -> bool:
208
+ return isinstance(other, UserPermission) and self.__hash__() == other.__hash__()
@@ -1,14 +1,14 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel, ConfigDict, Field, computed_field
2
2
 
3
3
 
4
4
  class ConnectorPaginationOptions(BaseModel):
5
5
  page: int = Field(default=1, ge=1)
6
- page_size: int = Field(default=25, gt=0, le=500)
6
+ page_size: int = Field(default=25, ge=1, le=500)
7
7
 
8
8
  @property
9
9
  def page_params(self) -> tuple[int, int]:
10
10
  if self.page is not None:
11
- return self.page, self.page_size
11
+ return (self.page, self.page_size)
12
12
  else:
13
13
  raise ValueError(
14
14
  "Pagination options must be set to return a page and page size",
@@ -0,0 +1,24 @@
1
+ # RBAC
2
+ CHAT_USER: str = "CHAT-USER"
3
+ ORG_ADMIN: str = "ORG-ADMIN"
4
+ TASK_ADMIN: str = "TASK-ADMIN"
5
+ DEFAULT_RULE_ADMIN: str = "DEFAULT-RULE-ADMIN"
6
+ VALIDATION_USER: str = "VALIDATION-USER"
7
+ ORG_AUDITOR: str = "ORG-AUDITOR"
8
+ ADMIN_KEY: str = "ADMIN-KEY"
9
+
10
+ LEGACY_KEYCLOAK_ROLES: dict[str, str] = {
11
+ "genai_engine_admin_user": TASK_ADMIN,
12
+ }
13
+
14
+ # Make sure the policy and description match
15
+ GENAI_ENGINE_KEYCLOAK_PASSWORD_LENGTH = 12
16
+ GENAI_ENGINE_KEYCLOAK_PASSWORD_POLICY = f"length({GENAI_ENGINE_KEYCLOAK_PASSWORD_LENGTH}) and specialChars(1) and upperCase(1) and lowerCase(1)"
17
+ ERROR_PASSWORD_POLICY_NOT_MET = f"Password should be at least {GENAI_ENGINE_KEYCLOAK_PASSWORD_LENGTH} characters and contain at least one special character, lowercase character, and uppercase character."
18
+ ERROR_DEFAULT_METRICS_ENGINE = "This metric could not be evaluated"
19
+
20
+ # Miscellaneous
21
+ DEFAULT_TOXICITY_RULE_THRESHOLD = 0.5
22
+ DEFAULT_PII_RULE_CONFIDENCE_SCORE_THRESHOLD = 0
23
+ NEGATIVE_BLOOD_EXAMPLE = "John has O negative blood group"
24
+ HALLUCINATION_RULE_NAME = "Hallucination Rule"
@@ -1,15 +1,6 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
- class ModelProblemType(str, Enum):
5
- REGRESSION = "regression"
6
- BINARY_CLASSIFICATION = "binary_classification"
7
- ARTHUR_SHIELD = "arthur_shield"
8
- CUSTOM = "custom"
9
- MULTICLASS_CLASSIFICATION = "multiclass_classification"
10
- AGENTIC_TRACE = "agentic_trace"
11
-
12
-
13
4
  class DatasetFileType(str, Enum):
14
5
  JSON = "json"
15
6
  CSV = "csv"
@@ -0,0 +1,144 @@
1
+ from enum import IntEnum, StrEnum
2
+
3
+ from arthur_common.models.constants import (
4
+ DEFAULT_RULE_ADMIN,
5
+ ORG_ADMIN,
6
+ ORG_AUDITOR,
7
+ TASK_ADMIN,
8
+ VALIDATION_USER,
9
+ )
10
+
11
+
12
+ class BaseEnum(StrEnum):
13
+ @classmethod
14
+ def values(self) -> list[str]:
15
+ values: list[str] = [e for e in self]
16
+ return values
17
+
18
+ def __str__(self) -> str:
19
+ return str(self.value)
20
+
21
+
22
+ class APIKeysRolesEnum(BaseEnum):
23
+ DEFAULT_RULE_ADMIN = DEFAULT_RULE_ADMIN
24
+ TASK_ADMIN = TASK_ADMIN
25
+ VALIDATION_USER = VALIDATION_USER
26
+ ORG_AUDITOR = ORG_AUDITOR
27
+ ORG_ADMIN = ORG_ADMIN
28
+
29
+
30
+ class InferenceFeedbackTarget(BaseEnum):
31
+ CONTEXT = "context"
32
+ RESPONSE_RESULTS = "response_results"
33
+ PROMPT_RESULTS = "prompt_results"
34
+
35
+
36
+ class MetricType(BaseEnum):
37
+ QUERY_RELEVANCE = "QueryRelevance"
38
+ RESPONSE_RELEVANCE = "ResponseRelevance"
39
+ TOOL_SELECTION = "ToolSelection"
40
+
41
+
42
+ class ModelProblemType(BaseEnum):
43
+ REGRESSION = "regression"
44
+ BINARY_CLASSIFICATION = "binary_classification"
45
+ ARTHUR_SHIELD = "arthur_shield"
46
+ CUSTOM = "custom"
47
+ MULTICLASS_CLASSIFICATION = "multiclass_classification"
48
+ AGENTIC_TRACE = "agentic_trace"
49
+
50
+
51
+ # Using version from arthur-engine, which has str and enum type inheritance.
52
+ # Note: These string values are not arbitrary and map to Presidio entity types: https://microsoft.github.io/presidio/supported_entities/
53
+ class PIIEntityTypes(BaseEnum):
54
+ CREDIT_CARD = "CREDIT_CARD"
55
+ CRYPTO = "CRYPTO"
56
+ DATE_TIME = "DATE_TIME"
57
+ EMAIL_ADDRESS = "EMAIL_ADDRESS"
58
+ IBAN_CODE = "IBAN_CODE"
59
+ IP_ADDRESS = "IP_ADDRESS"
60
+ NRP = "NRP"
61
+ LOCATION = "LOCATION"
62
+ PERSON = "PERSON"
63
+ PHONE_NUMBER = "PHONE_NUMBER"
64
+ MEDICAL_LICENSE = "MEDICAL_LICENSE"
65
+ URL = "URL"
66
+ US_BANK_NUMBER = "US_BANK_NUMBER"
67
+ US_DRIVER_LICENSE = "US_DRIVER_LICENSE"
68
+ US_ITIN = "US_ITIN"
69
+ US_PASSPORT = "US_PASSPORT"
70
+ US_SSN = "US_SSN"
71
+
72
+ @classmethod
73
+ def to_string(cls) -> str:
74
+ return ",".join(member.value for member in cls)
75
+
76
+
77
+ class PaginationSortMethod(BaseEnum):
78
+ ASCENDING = "asc"
79
+ DESCENDING = "desc"
80
+
81
+
82
+ class RuleResultEnum(BaseEnum):
83
+ PASS = "Pass"
84
+ FAIL = "Fail"
85
+ SKIPPED = "Skipped"
86
+ UNAVAILABLE = "Unavailable"
87
+ PARTIALLY_UNAVAILABLE = "Partially Unavailable"
88
+ MODEL_NOT_AVAILABLE = "Model Not Available"
89
+
90
+
91
+ class RuleScope(BaseEnum):
92
+ DEFAULT = "default"
93
+ TASK = "task"
94
+
95
+
96
+ class RuleType(BaseEnum):
97
+ KEYWORD = "KeywordRule"
98
+ MODEL_HALLUCINATION_V2 = "ModelHallucinationRuleV2"
99
+ MODEL_SENSITIVE_DATA = "ModelSensitiveDataRule"
100
+ PII_DATA = "PIIDataRule"
101
+ PROMPT_INJECTION = "PromptInjectionRule"
102
+ REGEX = "RegexRule"
103
+ TOXICITY = "ToxicityRule"
104
+
105
+
106
+ class TaskType(BaseEnum):
107
+ TRADITIONAL = "traditional"
108
+ AGENTIC = "agentic"
109
+
110
+
111
+ class TokenUsageScope(BaseEnum):
112
+ RULE_TYPE = "rule_type"
113
+ TASK = "task"
114
+
115
+
116
+ class ToolClassEnum(IntEnum):
117
+ WRONG_TOOL_SELECTED = 0
118
+ CORRECT_TOOL_SELECTED = 1
119
+ NO_TOOL_SELECTED = 2
120
+
121
+ def __str__(self) -> str:
122
+ return str(self.value)
123
+
124
+
125
+ class ToxicityViolationType(BaseEnum):
126
+ BENIGN = "benign"
127
+ HARMFUL_REQUEST = "harmful_request"
128
+ TOXIC_CONTENT = "toxic_content"
129
+ PROFANITY = "profanity"
130
+ UNKNOWN = "unknown"
131
+
132
+
133
+ # If you added values here, did you update permission_mappings.py in arthur-engine?
134
+ class UserPermissionAction(BaseEnum):
135
+ CREATE = "create"
136
+ READ = "read"
137
+
138
+
139
+ # If you added values here, did you update permission_mappings.py in arthur-engine?
140
+ class UserPermissionResource(BaseEnum):
141
+ PROMPTS = "prompts"
142
+ RESPONSES = "responses"
143
+ RULES = "rules"
144
+ TASKS = "tasks"
@@ -0,0 +1,63 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class RelevanceMetricConfig(BaseModel):
7
+ """Configuration for relevance metrics including QueryRelevance and ResponseRelevance"""
8
+
9
+ relevance_threshold: Optional[float] = Field(
10
+ default=None,
11
+ description="Threshold for determining relevance when not using LLM judge",
12
+ )
13
+ use_llm_judge: bool = Field(
14
+ default=True,
15
+ description="Whether to use LLM as a judge for relevance scoring",
16
+ )
17
+
18
+
19
+ class RelevanceMetric(BaseModel):
20
+ bert_f_score: Optional[float] = None
21
+ reranker_relevance_score: Optional[float] = None
22
+ llm_relevance_score: Optional[float] = None
23
+ reason: Optional[str] = None
24
+ refinement: Optional[str] = None
25
+
26
+
27
+ class QueryRelevanceMetric(RelevanceMetric):
28
+ """Inherits from RelevanceMetric. This class is left empty so that the openapi response schema remains the same as before, but we have a single source of truth for the relevance metric details."""
29
+
30
+
31
+ class ResponseRelevanceMetric(RelevanceMetric):
32
+ """Inherits from RelevanceMetric. This class is left empty so that the openapi response schema remains the same as before, but we have a single source of truth for the relevance metric details."""
33
+
34
+
35
+ class MetricRequest(BaseModel):
36
+ system_prompt: Optional[str] = Field(
37
+ description="System prompt to be used by GenAI Engine for computing metrics.",
38
+ default=None,
39
+ )
40
+ user_query: Optional[str] = Field(
41
+ description="User query to be used by GenAI Engine for computing metrics.",
42
+ default=None,
43
+ )
44
+ context: List[Dict[str, Any]] = Field(
45
+ description="Conversation history and additional context to be used by GenAI Engine for computing metrics.",
46
+ default_factory=list,
47
+ examples=[
48
+ {"role": "user", "value": "What is the weather in Tokyo?"},
49
+ {"role": "assistant", "value": "WeatherTool", "args": {"city": "Tokyo"}},
50
+ {
51
+ "role": "tool",
52
+ "value": '[{"name": "WeatherTool", "result": {"temperature": "20°C", "humidity": "50%", "condition": "sunny"}}]',
53
+ },
54
+ {
55
+ "role": "assistant",
56
+ "value": "The weather in Tokyo is sunny and the temperature is 20°C.",
57
+ },
58
+ ],
59
+ )
60
+ response: Optional[str] = Field(
61
+ description="Response to be used by GenAI Engine for computing metrics.",
62
+ default=None,
63
+ )
@@ -7,7 +7,7 @@ from uuid import UUID
7
7
  from pydantic import BaseModel, Field, field_validator, model_validator
8
8
  from typing_extensions import Self
9
9
 
10
- from arthur_common.models.datasets import ModelProblemType
10
+ from arthur_common.models.enums import ModelProblemType
11
11
  from arthur_common.models.schema_definitions import (
12
12
  DType,
13
13
  SchemaTypeUnion,