simplai-sdk 0.1.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.
- billing/__init__.py +6 -0
- billing/api.py +55 -0
- billing/client.py +14 -0
- billing/schema.py +15 -0
- constants/__init__.py +90 -0
- core/__init__.py +53 -0
- core/agents/__init__.py +42 -0
- core/agents/execution/__init__.py +49 -0
- core/agents/execution/api.py +283 -0
- core/agents/execution/client.py +1139 -0
- core/agents/models.py +99 -0
- core/workflows/WORKFLOW_ARCHITECTURE.md +417 -0
- core/workflows/__init__.py +31 -0
- core/workflows/bulk/__init__.py +14 -0
- core/workflows/bulk/api.py +202 -0
- core/workflows/bulk/client.py +115 -0
- core/workflows/bulk/schema.py +58 -0
- core/workflows/models.py +49 -0
- core/workflows/scheduling/__init__.py +9 -0
- core/workflows/scheduling/api.py +179 -0
- core/workflows/scheduling/client.py +128 -0
- core/workflows/scheduling/schema.py +74 -0
- core/workflows/tool_execution/__init__.py +16 -0
- core/workflows/tool_execution/api.py +172 -0
- core/workflows/tool_execution/client.py +195 -0
- core/workflows/tool_execution/schema.py +40 -0
- exceptions/__init__.py +21 -0
- simplai_sdk/__init__.py +7 -0
- simplai_sdk/simplai.py +239 -0
- simplai_sdk-0.1.0.dist-info/METADATA +728 -0
- simplai_sdk-0.1.0.dist-info/RECORD +42 -0
- simplai_sdk-0.1.0.dist-info/WHEEL +5 -0
- simplai_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
- simplai_sdk-0.1.0.dist-info/top_level.txt +7 -0
- traces/__init__.py +1 -0
- traces/agents/__init__.py +55 -0
- traces/agents/api.py +350 -0
- traces/agents/client.py +697 -0
- traces/agents/models.py +249 -0
- traces/workflows/__init__.py +0 -0
- utils/__init__.py +0 -0
- utils/config.py +117 -0
traces/agents/models.py
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class EvalMetrics:
|
|
10
|
+
"""Evaluation metrics for a trace."""
|
|
11
|
+
metric: str
|
|
12
|
+
score: Optional[float] = None
|
|
13
|
+
status: Optional[str] = None
|
|
14
|
+
passing_threshold: Optional[float] = None
|
|
15
|
+
desc: Optional[str] = None
|
|
16
|
+
failed_remark: Optional[str] = None
|
|
17
|
+
evaluated_at: Optional[datetime] = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class RagTrace:
|
|
22
|
+
"""Request-level trace (RAG trace) representing an agent conversation."""
|
|
23
|
+
id: Optional[str] = None
|
|
24
|
+
request_id: Optional[str] = None
|
|
25
|
+
conversation_id: Optional[str] = None
|
|
26
|
+
user_id: Optional[int] = None
|
|
27
|
+
username: Optional[str] = None
|
|
28
|
+
tenant_id: Optional[int] = None
|
|
29
|
+
workflow_id: Optional[str] = None
|
|
30
|
+
workflow_name: Optional[str] = None
|
|
31
|
+
agent_id: Optional[str] = None
|
|
32
|
+
agent_name: Optional[str] = None
|
|
33
|
+
kb_id: Optional[int] = None
|
|
34
|
+
kb_name: Optional[str] = None
|
|
35
|
+
model_id: Optional[str] = None
|
|
36
|
+
model_name: Optional[str] = None
|
|
37
|
+
model_input_tokens: Optional[int] = None
|
|
38
|
+
model_output_tokens: Optional[int] = None
|
|
39
|
+
kb_query_tokens: Optional[int] = None
|
|
40
|
+
context_tokens: Optional[int] = None
|
|
41
|
+
query: Optional[str] = None
|
|
42
|
+
prompt: Optional[str] = None
|
|
43
|
+
context: Optional[List[str]] = None
|
|
44
|
+
response: Optional[str] = None
|
|
45
|
+
response_time: Optional[int] = None
|
|
46
|
+
model_response_time: Optional[int] = None
|
|
47
|
+
kb_response_time: Optional[int] = None
|
|
48
|
+
user_feedback: Optional[bool] = None
|
|
49
|
+
source: List[str] = field(default_factory=list)
|
|
50
|
+
created_at: Optional[datetime] = None
|
|
51
|
+
updated_at: Optional[datetime] = None
|
|
52
|
+
evaluation_started_by: Optional[int] = None
|
|
53
|
+
evaluation_started_by_name: Optional[str] = None
|
|
54
|
+
eval_metrics: Optional[List[EvalMetrics]] = None
|
|
55
|
+
status: Optional[str] = None
|
|
56
|
+
ground_truth: Optional[str] = None
|
|
57
|
+
payload: Optional[Dict[str, Any]] = None # Full API response
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class TraceData:
|
|
62
|
+
"""Data payload for a trace node."""
|
|
63
|
+
input: Optional[Dict[str, Any]] = None
|
|
64
|
+
output: Optional[Dict[str, Any]] = None
|
|
65
|
+
error: Optional[str] = None
|
|
66
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class ChildInfo:
|
|
71
|
+
"""Information about a child node."""
|
|
72
|
+
node_id: str
|
|
73
|
+
name: str
|
|
74
|
+
entity_type: Optional[str] = None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class TraceNode:
|
|
79
|
+
"""Tree-based trace node representing a step in agent/workflow execution."""
|
|
80
|
+
id: Optional[str] = None
|
|
81
|
+
tenant_id: Optional[int] = None
|
|
82
|
+
project_id: Optional[int] = None
|
|
83
|
+
user_id: Optional[int] = None
|
|
84
|
+
source: Optional[str] = None
|
|
85
|
+
is_bulk_run_parent: Optional[bool] = None
|
|
86
|
+
node_id: Optional[str] = None # span id
|
|
87
|
+
name: Optional[str] = None # step name (tool name, agent name, etc.)
|
|
88
|
+
entity_type: Optional[str] = None # agent, tool, step, model, kb
|
|
89
|
+
entity_id: Optional[str] = None
|
|
90
|
+
tree_id: Optional[str] = None
|
|
91
|
+
parent_id: Optional[str] = None
|
|
92
|
+
parent_span_id: Optional[str] = None
|
|
93
|
+
children: Optional[List[TraceNode]] = None
|
|
94
|
+
descendants: Optional[List[ChildInfo]] = None
|
|
95
|
+
path: Optional[str] = None # ancestor chain based on node name
|
|
96
|
+
data: Optional[TraceData] = None
|
|
97
|
+
has_children: Optional[bool] = None
|
|
98
|
+
created_at: Optional[datetime] = None
|
|
99
|
+
execution_time: Optional[datetime] = None
|
|
100
|
+
profile_id: Optional[str] = None
|
|
101
|
+
profile: Optional[str] = None
|
|
102
|
+
is_root: Optional[bool] = None
|
|
103
|
+
sub_entity_id: Optional[str] = None
|
|
104
|
+
completion_tokens: Optional[int] = None
|
|
105
|
+
prompt_tokens: Optional[int] = None
|
|
106
|
+
total_tokens: Optional[int] = None
|
|
107
|
+
latency: Optional[float] = None
|
|
108
|
+
context_window_utilization: Optional[float] = None
|
|
109
|
+
status: Optional[str] = None
|
|
110
|
+
origin: Optional[str] = None
|
|
111
|
+
app_id: Optional[str] = None
|
|
112
|
+
child_count: Optional[int] = None
|
|
113
|
+
payload: Optional[Dict[str, Any]] = None # Full API response
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class FetchTraceFilters:
|
|
118
|
+
"""Filters for fetching request-level traces (RAG traces)."""
|
|
119
|
+
tenant_id: Optional[int] = None
|
|
120
|
+
user_id: Optional[int] = None
|
|
121
|
+
request_id: Optional[str] = None
|
|
122
|
+
query: Optional[str] = None
|
|
123
|
+
workflow_id: Optional[str] = None
|
|
124
|
+
agent_id: Optional[str] = None
|
|
125
|
+
is_agent: Optional[bool] = None
|
|
126
|
+
kb_id: Optional[int] = None
|
|
127
|
+
model_id: Optional[str] = None
|
|
128
|
+
search_filter: Optional[str] = None
|
|
129
|
+
created_at_from: Optional[datetime] = None
|
|
130
|
+
created_at_to: Optional[datetime] = None
|
|
131
|
+
|
|
132
|
+
def to_query_params(self) -> Dict[str, Any]:
|
|
133
|
+
"""Convert filters to query parameters."""
|
|
134
|
+
params: Dict[str, Any] = {}
|
|
135
|
+
if self.user_id is not None:
|
|
136
|
+
params["userId"] = str(self.user_id)
|
|
137
|
+
if self.request_id:
|
|
138
|
+
params["requestId"] = self.request_id
|
|
139
|
+
if self.query:
|
|
140
|
+
params["query"] = self.query
|
|
141
|
+
if self.workflow_id:
|
|
142
|
+
params["workflowId"] = self.workflow_id
|
|
143
|
+
if self.agent_id:
|
|
144
|
+
params["agentId"] = self.agent_id
|
|
145
|
+
if self.is_agent is not None:
|
|
146
|
+
params["isAgent"] = str(self.is_agent).lower()
|
|
147
|
+
if self.kb_id is not None:
|
|
148
|
+
params["kbId"] = str(self.kb_id)
|
|
149
|
+
if self.model_id:
|
|
150
|
+
params["modelId"] = self.model_id
|
|
151
|
+
if self.search_filter:
|
|
152
|
+
params["searchFilter"] = self.search_filter
|
|
153
|
+
if self.created_at_from:
|
|
154
|
+
params["createdAtFrom"] = self.created_at_from.strftime("%Y-%m-%d %H:%M:%S")
|
|
155
|
+
if self.created_at_to:
|
|
156
|
+
params["createdAtTo"] = self.created_at_to.strftime("%Y-%m-%d %H:%M:%S")
|
|
157
|
+
return params
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@dataclass
|
|
161
|
+
class TraceFilters:
|
|
162
|
+
"""Filters for fetching tree-based traces."""
|
|
163
|
+
tenant_id: Optional[int] = None
|
|
164
|
+
user_id: Optional[int] = None
|
|
165
|
+
project_id: Optional[int] = None
|
|
166
|
+
path: Optional[str] = None
|
|
167
|
+
name: Optional[str] = None
|
|
168
|
+
source: Optional[List[str]] = None
|
|
169
|
+
is_get_all: bool = False
|
|
170
|
+
profile: Optional[str] = None
|
|
171
|
+
profile_id: Optional[str] = None
|
|
172
|
+
entity_id: Optional[str] = None
|
|
173
|
+
sub_entity_id: Optional[str] = None
|
|
174
|
+
version: Optional[str] = None
|
|
175
|
+
status: Optional[List[str]] = None
|
|
176
|
+
origin: Optional[List[str]] = None
|
|
177
|
+
created_at_from: Optional[datetime] = None
|
|
178
|
+
created_at_to: Optional[datetime] = None
|
|
179
|
+
|
|
180
|
+
def to_query_params(self) -> Dict[str, Any]:
|
|
181
|
+
"""Convert filters to query parameters."""
|
|
182
|
+
params: Dict[str, Any] = {}
|
|
183
|
+
if self.user_id is not None:
|
|
184
|
+
params["userId"] = str(self.user_id)
|
|
185
|
+
if self.path:
|
|
186
|
+
params["path"] = self.path
|
|
187
|
+
if self.name:
|
|
188
|
+
params["name"] = self.name
|
|
189
|
+
if self.source:
|
|
190
|
+
params["source"] = ",".join(self.source)
|
|
191
|
+
if self.is_get_all:
|
|
192
|
+
params["isGetAll"] = "true"
|
|
193
|
+
if self.profile:
|
|
194
|
+
params["profile"] = self.profile
|
|
195
|
+
if self.profile_id:
|
|
196
|
+
params["profileId"] = self.profile_id
|
|
197
|
+
if self.entity_id:
|
|
198
|
+
params["entityId"] = self.entity_id
|
|
199
|
+
if self.sub_entity_id:
|
|
200
|
+
params["subEntityId"] = self.sub_entity_id
|
|
201
|
+
if self.version:
|
|
202
|
+
params["version"] = self.version
|
|
203
|
+
if self.status:
|
|
204
|
+
params["status"] = ",".join(self.status)
|
|
205
|
+
if self.origin:
|
|
206
|
+
params["origin"] = ",".join(self.origin)
|
|
207
|
+
if self.created_at_from:
|
|
208
|
+
params["createdAtFrom"] = self.created_at_from.strftime("%Y-%m-%d %H:%M:%S")
|
|
209
|
+
if self.created_at_to:
|
|
210
|
+
params["createdAtTo"] = self.created_at_to.strftime("%Y-%m-%d %H:%M:%S")
|
|
211
|
+
return params
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass
|
|
215
|
+
class MetricsRequestDto:
|
|
216
|
+
"""Request DTO for fetching metrics."""
|
|
217
|
+
tenant_id: Optional[int] = None
|
|
218
|
+
project_id: Optional[int] = None
|
|
219
|
+
app_id: Optional[str] = None
|
|
220
|
+
from_date: Optional[datetime] = None
|
|
221
|
+
to_date: Optional[datetime] = None
|
|
222
|
+
|
|
223
|
+
def to_query_params(self) -> Dict[str, Any]:
|
|
224
|
+
"""Convert to query parameters."""
|
|
225
|
+
params: Dict[str, Any] = {}
|
|
226
|
+
if self.app_id:
|
|
227
|
+
params["appId"] = self.app_id
|
|
228
|
+
if self.from_date:
|
|
229
|
+
params["fromDate"] = self.from_date.strftime("%Y-%m-%d %H:%M:%S")
|
|
230
|
+
if self.to_date:
|
|
231
|
+
params["toDate"] = self.to_date.strftime("%Y-%m-%d %H:%M:%S")
|
|
232
|
+
return params
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@dataclass
|
|
236
|
+
class PageableResponse:
|
|
237
|
+
"""Paginated response wrapper."""
|
|
238
|
+
success: bool
|
|
239
|
+
status: str
|
|
240
|
+
data: Any # Can be Page[RagTrace] or Page[TraceNode]
|
|
241
|
+
total_elements: Optional[int] = None
|
|
242
|
+
total_pages: Optional[int] = None
|
|
243
|
+
page_number: Optional[int] = None
|
|
244
|
+
page_size: Optional[int] = None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class TraceError(Exception):
|
|
248
|
+
"""Raised when a trace operation fails."""
|
|
249
|
+
|
|
File without changes
|
utils/__init__.py
ADDED
|
File without changes
|
utils/config.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Configuration utilities for loading API keys and base URLs.
|
|
2
|
+
|
|
3
|
+
This module provides utilities to load configuration values with the following priority:
|
|
4
|
+
1. User-provided parameter
|
|
5
|
+
2. Environment variable
|
|
6
|
+
3. .env file (if python-dotenv is available)
|
|
7
|
+
4. Default value (for base_url) or error (for api_key)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _load_env_file() -> None:
|
|
16
|
+
"""Attempt to load .env file from common locations."""
|
|
17
|
+
try:
|
|
18
|
+
from dotenv import load_dotenv
|
|
19
|
+
except ImportError:
|
|
20
|
+
# python-dotenv not installed, skip loading .env
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
# Try to find .env file in common locations
|
|
24
|
+
current_dir = Path.cwd()
|
|
25
|
+
possible_env_paths = [
|
|
26
|
+
current_dir / ".env",
|
|
27
|
+
current_dir.parent / ".env", # python-sdk/.env
|
|
28
|
+
Path(__file__).parent.parent.parent / ".env", # python-sdk/.env from src/utils
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
for env_path in possible_env_paths:
|
|
32
|
+
if env_path.exists():
|
|
33
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
34
|
+
break
|
|
35
|
+
else:
|
|
36
|
+
# Fallback: try loading from current directory
|
|
37
|
+
load_dotenv(override=False)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_api_key(api_key: Optional[str] = None) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Get API key with fallback priority:
|
|
43
|
+
1. User-provided api_key parameter
|
|
44
|
+
2. API_KEY from environment variable
|
|
45
|
+
3. API_KEY from .env file
|
|
46
|
+
4. Raise error if not found
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
api_key: Optional API key provided by user
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
API key string
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If API key is not found in any source
|
|
56
|
+
"""
|
|
57
|
+
# First priority: user-provided API key
|
|
58
|
+
if api_key:
|
|
59
|
+
return api_key
|
|
60
|
+
|
|
61
|
+
# Second priority: check environment variable (may already be set)
|
|
62
|
+
env_api_key = os.getenv("SIMPAI_API_KEY")
|
|
63
|
+
if env_api_key:
|
|
64
|
+
return env_api_key
|
|
65
|
+
|
|
66
|
+
# Third priority: try to load from .env file
|
|
67
|
+
_load_env_file()
|
|
68
|
+
|
|
69
|
+
# Check environment variable again after loading .env
|
|
70
|
+
env_api_key = os.getenv("SIMPAI_API_KEY")
|
|
71
|
+
if env_api_key:
|
|
72
|
+
return env_api_key
|
|
73
|
+
|
|
74
|
+
# Fourth priority: raise error
|
|
75
|
+
raise ValueError(
|
|
76
|
+
"API key is required. Provide it using one of the following methods:\n"
|
|
77
|
+
" 1. As a parameter: SimplAI(api_key='your-key')\n"
|
|
78
|
+
" 2. As environment variable: export API_KEY=your-key\n"
|
|
79
|
+
" 3. In a .env file: API_KEY=your-key"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_base_url(base_url: Optional[str] = None) -> str:
|
|
84
|
+
"""
|
|
85
|
+
Get base URL with fallback priority:
|
|
86
|
+
1. User-provided base_url parameter
|
|
87
|
+
2. BASE_URL from environment variable
|
|
88
|
+
3. BASE_URL from .env file
|
|
89
|
+
4. Default base URL constant
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
base_url: Optional base URL provided by user
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Base URL string
|
|
96
|
+
"""
|
|
97
|
+
# First priority: user-provided base URL
|
|
98
|
+
if base_url:
|
|
99
|
+
return base_url.rstrip("/")
|
|
100
|
+
|
|
101
|
+
# Second priority: check environment variable (may already be set)
|
|
102
|
+
env_base_url = os.getenv("SIMPAI_BASE_URL")
|
|
103
|
+
if env_base_url:
|
|
104
|
+
return env_base_url.rstrip("/")
|
|
105
|
+
|
|
106
|
+
# Third priority: try to load from .env file
|
|
107
|
+
_load_env_file()
|
|
108
|
+
|
|
109
|
+
# Check environment variable again after loading .env
|
|
110
|
+
env_base_url = os.getenv("SIMPAI_BASE_URL")
|
|
111
|
+
if env_base_url:
|
|
112
|
+
return env_base_url.rstrip("/")
|
|
113
|
+
|
|
114
|
+
# Fourth priority: default base URL
|
|
115
|
+
from constants import DEFAULT_BASE_URL
|
|
116
|
+
|
|
117
|
+
return DEFAULT_BASE_URL
|