wexa-sdk 0.1.0__py3-none-any.whl → 0.1.6__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.
- wexa_sdk/agentflows.py +89 -4
- wexa_sdk/connectors/core.py +31 -3
- wexa_sdk/core/__init__.py +1 -0
- wexa_sdk/core/http.py +86 -0
- wexa_sdk/files.py +9 -2
- wexa_sdk/projects.py +106 -6
- wexa_sdk/skills.py +25 -3
- wexa_sdk/tables.py +58 -2
- {wexa_sdk-0.1.0.dist-info → wexa_sdk-0.1.6.dist-info}/METADATA +1 -1
- {wexa_sdk-0.1.0.dist-info → wexa_sdk-0.1.6.dist-info}/RECORD +12 -10
- {wexa_sdk-0.1.0.dist-info → wexa_sdk-0.1.6.dist-info}/WHEEL +0 -0
- {wexa_sdk-0.1.0.dist-info → wexa_sdk-0.1.6.dist-info}/top_level.txt +0 -0
wexa_sdk/agentflows.py
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional, TypedDict
|
|
1
3
|
from .core.http import HttpClient
|
|
2
4
|
|
|
5
|
+
|
|
6
|
+
class AgentflowCreateBody(TypedDict, total=False):
|
|
7
|
+
"""Body for creating an AgentFlow (Coworker).
|
|
8
|
+
|
|
9
|
+
Required:
|
|
10
|
+
- name: str
|
|
11
|
+
- description: str
|
|
12
|
+
- role: str
|
|
13
|
+
- projectID: str
|
|
14
|
+
|
|
15
|
+
Optional: backend-supported fields like agents/processflow, anomaly_detection, cron_details, etc.
|
|
16
|
+
"""
|
|
17
|
+
name: str
|
|
18
|
+
description: str
|
|
19
|
+
role: str
|
|
20
|
+
projectID: str
|
|
21
|
+
|
|
3
22
|
class AgentFlows:
|
|
4
23
|
def __init__(self, http: HttpClient):
|
|
5
24
|
self.http = http
|
|
@@ -27,11 +46,77 @@ class AgentFlows:
|
|
|
27
46
|
def get(self, id: str):
|
|
28
47
|
return self.http.request("GET", f"/agentflow/{id}")
|
|
29
48
|
|
|
30
|
-
def create(self, body:
|
|
31
|
-
|
|
49
|
+
def create(self, body: AgentflowCreateBody, projectID: Optional[str] = None):
|
|
50
|
+
"""
|
|
51
|
+
Create a new AgentFlow (Coworker).
|
|
52
|
+
|
|
53
|
+
Query params:
|
|
54
|
+
- projectID (str, required): Project to create the AgentFlow in. If not provided
|
|
55
|
+
as an argument, this will be inferred from body['projectID'] or body['projectId'].
|
|
56
|
+
|
|
57
|
+
Headers:
|
|
58
|
+
- x-api-key (str, required)
|
|
59
|
+
|
|
60
|
+
Body (application/json):
|
|
61
|
+
- name (str, required)
|
|
62
|
+
- description (str, required)
|
|
63
|
+
- role (str, required)
|
|
64
|
+
- projectID (str, required)
|
|
65
|
+
- ...additional optional fields supported by backend (e.g., agents, anomaly_detection, cron_details)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
- dict: The created AgentFlow JSON (e.g., keys: _id, name, role, projectID, ...)
|
|
69
|
+
"""
|
|
70
|
+
# include projectID in query if provided, or infer from body
|
|
71
|
+
pid = projectID or body.get("projectID") or body.get("projectId")
|
|
72
|
+
params = {"projectID": pid} if pid else None
|
|
73
|
+
return self.http.request("POST", "/agentflow/", params=params, json=body)
|
|
32
74
|
|
|
33
75
|
def update(self, id: str, body: dict):
|
|
34
76
|
return self.http.request("PUT", f"/agentflow/{id}", json=body)
|
|
35
77
|
|
|
36
|
-
|
|
37
|
-
|
|
78
|
+
# Typed body for updating a skilled agent to enable IDE suggestions
|
|
79
|
+
class UpdateSkilledAgentBody(TypedDict, total=False):
|
|
80
|
+
"""Body for updating a skilled agent within an AgentFlow.
|
|
81
|
+
|
|
82
|
+
Required (per API docs):
|
|
83
|
+
- role: str
|
|
84
|
+
- title: str
|
|
85
|
+
- skills: list[str]
|
|
86
|
+
- prompt: { template: str, variables: list, display_template: str }
|
|
87
|
+
- context: list
|
|
88
|
+
- triggers: list
|
|
89
|
+
- llm: { model: str, max_tokens: int, temperature: int }
|
|
90
|
+
- role_description: str
|
|
91
|
+
- memory: { memory_type: str }
|
|
92
|
+
- has_knowledge_base: bool
|
|
93
|
+
- is_user_specific_task: bool
|
|
94
|
+
- is_preview_mode_enabled: bool
|
|
95
|
+
"""
|
|
96
|
+
role: str
|
|
97
|
+
title: str
|
|
98
|
+
skills: list[str]
|
|
99
|
+
prompt: dict
|
|
100
|
+
context: list
|
|
101
|
+
triggers: list
|
|
102
|
+
llm: dict
|
|
103
|
+
role_description: str
|
|
104
|
+
memory: dict
|
|
105
|
+
has_knowledge_base: bool
|
|
106
|
+
is_user_specific_task: bool
|
|
107
|
+
is_preview_mode_enabled: bool
|
|
108
|
+
|
|
109
|
+
def update_skilled_agent(self, agentflow_id: str, agent_id: str, *, projectID: str, body: UpdateSkilledAgentBody | dict):
|
|
110
|
+
"""Update a skilled agent within an AgentFlow.
|
|
111
|
+
|
|
112
|
+
Endpoint: POST /agentflow/{agentflow_id}/update/skilled/{agent_id}?projectID=...
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
agentflow_id: ID of the AgentFlow
|
|
116
|
+
agent_id: ID of the skilled agent inside the AgentFlow
|
|
117
|
+
projectID: Project ID (query param, required)
|
|
118
|
+
body: Update payload, see UpdateSkilledAgentBody for suggested keys
|
|
119
|
+
"""
|
|
120
|
+
params = {"projectID": projectID} if projectID else None
|
|
121
|
+
path = f"/agentflow/{agentflow_id}/update/skilled/{agent_id}"
|
|
122
|
+
return self.http.request("POST", path, params=params, json=body)
|
wexa_sdk/connectors/core.py
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Any, Optional
|
|
2
|
+
from typing import Any, Optional, TypedDict
|
|
3
3
|
|
|
4
4
|
from ..core.http import HttpClient
|
|
5
5
|
from .google_drive import GoogleDrive
|
|
6
6
|
|
|
7
|
+
class ConnectorConfigBody(TypedDict, total=False):
|
|
8
|
+
"""JSON body for configuring a connector via POST /actions/{CATEGORY}/config.
|
|
9
|
+
|
|
10
|
+
Required by backend (typical fields):
|
|
11
|
+
- name: str
|
|
12
|
+
- description: str
|
|
13
|
+
- category: str
|
|
14
|
+
- org_id: str
|
|
15
|
+
- projectID: str # NOTE: camelCase as required by backend
|
|
16
|
+
- logo: str
|
|
17
|
+
- ui_form: list
|
|
18
|
+
|
|
19
|
+
Optional/variable:
|
|
20
|
+
- config: dict
|
|
21
|
+
- enabled: bool
|
|
22
|
+
"""
|
|
23
|
+
name: str
|
|
24
|
+
description: str
|
|
25
|
+
category: str
|
|
26
|
+
org_id: str
|
|
27
|
+
projectID: str
|
|
28
|
+
logo: str
|
|
29
|
+
ui_form: list
|
|
30
|
+
config: dict
|
|
31
|
+
enabled: bool
|
|
32
|
+
|
|
7
33
|
class Connectors:
|
|
8
34
|
def __init__(self, http: HttpClient):
|
|
9
35
|
self.http = http
|
|
@@ -16,8 +42,10 @@ class Connectors:
|
|
|
16
42
|
return self.http.request("POST", path, params=params, json=body)
|
|
17
43
|
|
|
18
44
|
# POST /actions/{CATEGORY}/config?projectID=...
|
|
19
|
-
def set_config(self, category: str, project_id: str, body: dict) -> Any:
|
|
20
|
-
|
|
45
|
+
def set_config(self, category: str, project_id: str, body: ConnectorConfigBody | dict) -> Any:
|
|
46
|
+
# Ensure body contains the required camelCase field expected by the backend
|
|
47
|
+
json_body = {**(body or {}), "projectID": project_id}
|
|
48
|
+
return self.http.request("POST", f"/actions/{category}/config", params={"projectID": project_id}, json=json_body)
|
|
21
49
|
|
|
22
50
|
# GET /actions/{CATEGORY}/config/{projectID}
|
|
23
51
|
def get_config(self, category: str, project_id: str) -> Any:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .http import HttpClient, ApiError
|
wexa_sdk/core/http.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
RETRY_STATUS = {429, 500, 502, 503, 504}
|
|
9
|
+
|
|
10
|
+
class ApiError(Exception):
|
|
11
|
+
def __init__(self, status: int, detail: Optional[str] = None, code: Optional[str] = None, request_id: Optional[str] = None, raw: Any = None):
|
|
12
|
+
super().__init__(detail or f"API Error {status}")
|
|
13
|
+
self.status = status
|
|
14
|
+
self.code = code
|
|
15
|
+
self.detail = detail
|
|
16
|
+
self.request_id = request_id
|
|
17
|
+
self.raw = raw
|
|
18
|
+
|
|
19
|
+
class HttpClient:
|
|
20
|
+
def __init__(self, base_url: str, api_key: str, user_agent: Optional[str] = None, timeout: Optional[dict] = None, retries: Optional[dict] = None):
|
|
21
|
+
self.base_url = base_url.rstrip("/")
|
|
22
|
+
self.api_key = api_key
|
|
23
|
+
self.user_agent = user_agent
|
|
24
|
+
self.timeout = {
|
|
25
|
+
"connectTimeoutMs": (timeout or {}).get("connectTimeoutMs", 5000),
|
|
26
|
+
"readTimeoutMs": (timeout or {}).get("readTimeoutMs", 30000),
|
|
27
|
+
}
|
|
28
|
+
self.retries = {
|
|
29
|
+
"attempts": (retries or {}).get("attempts", 3),
|
|
30
|
+
"baseDelayMs": (retries or {}).get("baseDelayMs", 500),
|
|
31
|
+
"maxDelayMs": (retries or {}).get("maxDelayMs", 30000),
|
|
32
|
+
}
|
|
33
|
+
self._client = httpx.Client(timeout=self.timeout["readTimeoutMs"] / 1000)
|
|
34
|
+
|
|
35
|
+
def request(self, method: str, path: str, *, params: Optional[Dict[str, Any]] = None, json: Any = None, headers: Optional[Dict[str, str]] = None):
|
|
36
|
+
url = f"{self.base_url}{path}"
|
|
37
|
+
hdrs = {
|
|
38
|
+
"content-type": "application/json",
|
|
39
|
+
"x-api-key": self.api_key,
|
|
40
|
+
"X-Wexa-SDK-Version": "py/0.1.0",
|
|
41
|
+
}
|
|
42
|
+
if self.user_agent:
|
|
43
|
+
hdrs["User-Agent"] = self.user_agent
|
|
44
|
+
if headers:
|
|
45
|
+
hdrs.update(headers)
|
|
46
|
+
|
|
47
|
+
req_id = headers.get("x-client-request-id") if headers else None
|
|
48
|
+
if not req_id:
|
|
49
|
+
req_id = str(int(time.time() * 1000))
|
|
50
|
+
hdrs["x-client-request-id"] = req_id
|
|
51
|
+
|
|
52
|
+
attempt = 0
|
|
53
|
+
last_err: Optional[Exception] = None
|
|
54
|
+
while attempt < self.retries["attempts"]:
|
|
55
|
+
try:
|
|
56
|
+
resp = self._client.request(method, url, params=params, json=json, headers=hdrs)
|
|
57
|
+
res_req_id = resp.headers.get("x-request-id") or req_id
|
|
58
|
+
text = resp.text
|
|
59
|
+
try:
|
|
60
|
+
data = resp.json() if text else None
|
|
61
|
+
except Exception:
|
|
62
|
+
data = text
|
|
63
|
+
if not resp.is_success:
|
|
64
|
+
detail = (isinstance(data, dict) and (data.get("detail") or data.get("error") or data.get("message"))) or text or f"HTTP {resp.status_code}"
|
|
65
|
+
if resp.status_code in RETRY_STATUS and attempt < self.retries["attempts"] - 1:
|
|
66
|
+
time.sleep(self._backoff(attempt) / 1000)
|
|
67
|
+
attempt += 1
|
|
68
|
+
continue
|
|
69
|
+
raise ApiError(status=resp.status_code, detail=detail, request_id=res_req_id, raw=data)
|
|
70
|
+
return data
|
|
71
|
+
except ApiError:
|
|
72
|
+
raise
|
|
73
|
+
except Exception as e: # network error
|
|
74
|
+
last_err = e
|
|
75
|
+
if attempt < self.retries["attempts"] - 1:
|
|
76
|
+
time.sleep(self._backoff(attempt) / 1000)
|
|
77
|
+
attempt += 1
|
|
78
|
+
continue
|
|
79
|
+
raise ApiError(status=0, detail=str(e), request_id=req_id, raw=e)
|
|
80
|
+
raise last_err # type: ignore
|
|
81
|
+
|
|
82
|
+
def _backoff(self, attempt: int) -> int:
|
|
83
|
+
import random
|
|
84
|
+
jitter = random.random() * 0.2 + 0.9
|
|
85
|
+
delay = min(self.retries["maxDelayMs"], int(self.retries["baseDelayMs"] * (2 ** attempt)))
|
|
86
|
+
return int(delay * jitter)
|
wexa_sdk/files.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Any, Dict, Optional
|
|
2
|
+
from typing import Any, Dict, Optional, TypedDict
|
|
3
3
|
|
|
4
4
|
from .core.http import HttpClient
|
|
5
5
|
|
|
@@ -9,7 +9,14 @@ class Files:
|
|
|
9
9
|
|
|
10
10
|
# POST /files/upload?projectID=...&container_name=...
|
|
11
11
|
# body example: { "filenames": ["file.pdf"], "tags": ["resume"], "source_type": "STORAGE", "org_id": "..." }
|
|
12
|
-
|
|
12
|
+
class UploadFilesBody(TypedDict):
|
|
13
|
+
filenames: list[str]
|
|
14
|
+
tags: list[str]
|
|
15
|
+
projectID: str
|
|
16
|
+
source_type: str
|
|
17
|
+
org_id: str
|
|
18
|
+
|
|
19
|
+
def upload_request(self, project_id: str, container_name: str, body: UploadFilesBody):
|
|
13
20
|
params: Dict[str, Any] = {"projectID": project_id, "container_name": container_name}
|
|
14
21
|
return self.http.request("POST", "/files/upload", params=params, json=body)
|
|
15
22
|
|
wexa_sdk/projects.py
CHANGED
|
@@ -1,33 +1,133 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Optional, Dict, Any
|
|
2
|
+
from typing import Optional, Dict, Any, TypedDict
|
|
3
3
|
|
|
4
4
|
from .core.http import HttpClient
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
class ProjectCreateBody(TypedDict, total=False):
|
|
8
|
+
"""Body for creating a project.
|
|
9
|
+
|
|
10
|
+
Required fields:
|
|
11
|
+
- orgId: str
|
|
12
|
+
- projectName: str
|
|
13
|
+
|
|
14
|
+
Optional fields:
|
|
15
|
+
- description: str
|
|
16
|
+
- coworker_role: str
|
|
17
|
+
- status: str (e.g., "published")
|
|
18
|
+
"""
|
|
19
|
+
orgId: str
|
|
20
|
+
projectName: str
|
|
21
|
+
description: str
|
|
22
|
+
coworker_role: str
|
|
23
|
+
status: str
|
|
24
|
+
|
|
6
25
|
class Projects:
|
|
7
26
|
def __init__(self, http: HttpClient):
|
|
8
27
|
self.http = http
|
|
9
28
|
|
|
10
29
|
# Per developers.wexa.ai: POST https://api.wexa.ai/v1/project
|
|
11
|
-
def create(self, body:
|
|
30
|
+
def create(self, body: ProjectCreateBody):
|
|
12
31
|
"""
|
|
13
|
-
|
|
32
|
+
Create a project with a request body.
|
|
33
|
+
|
|
34
|
+
Example body:
|
|
14
35
|
{
|
|
15
36
|
"orgId": "67fdea40aac77be632954f0f",
|
|
16
37
|
"projectName": "New",
|
|
17
38
|
"description": "yoooo",
|
|
18
|
-
"coworker_role": "testrole"
|
|
39
|
+
"coworker_role": "testrole",
|
|
40
|
+
"status": "published"
|
|
19
41
|
}
|
|
20
42
|
"""
|
|
21
43
|
return self.http.request("POST", "/v1/project", json=body)
|
|
22
44
|
|
|
45
|
+
def create_simple(
|
|
46
|
+
self,
|
|
47
|
+
*,
|
|
48
|
+
orgId: str,
|
|
49
|
+
projectName: str,
|
|
50
|
+
description: Optional[str] = None,
|
|
51
|
+
coworker_role: Optional[str] = None,
|
|
52
|
+
status: Optional[str] = None,
|
|
53
|
+
):
|
|
54
|
+
"""Convenience wrapper: builds the body and calls create(body)."""
|
|
55
|
+
body: Dict[str, Any] = {"orgId": orgId, "projectName": projectName}
|
|
56
|
+
if description is not None:
|
|
57
|
+
body["description"] = description
|
|
58
|
+
if coworker_role is not None:
|
|
59
|
+
body["coworker_role"] = coworker_role
|
|
60
|
+
if status is not None:
|
|
61
|
+
body["status"] = status
|
|
62
|
+
return self.create(body) # type: ignore[arg-type]
|
|
63
|
+
|
|
23
64
|
def list(self):
|
|
24
65
|
return self.http.request("GET", "/v1/project")
|
|
25
66
|
|
|
67
|
+
def list_all(self, user_id: str):
|
|
68
|
+
"""
|
|
69
|
+
Get all projects for a given user (organization-wide).
|
|
70
|
+
GET /v1/project/all?userId=...
|
|
71
|
+
|
|
72
|
+
Headers:
|
|
73
|
+
- x-api-key: string (required)
|
|
74
|
+
|
|
75
|
+
Query params:
|
|
76
|
+
- userId: string (required)
|
|
77
|
+
"""
|
|
78
|
+
params = {"userId": user_id}
|
|
79
|
+
return self.http.request("GET", "/v1/project/all", params=params)
|
|
80
|
+
|
|
81
|
+
def get_all(
|
|
82
|
+
self,
|
|
83
|
+
*,
|
|
84
|
+
status: Optional[str] = None,
|
|
85
|
+
user_id: Optional[str] = None,
|
|
86
|
+
org_id: Optional[str] = None,
|
|
87
|
+
page: Optional[int] = None,
|
|
88
|
+
limit: Optional[int] = None,
|
|
89
|
+
):
|
|
90
|
+
"""
|
|
91
|
+
Get all projects with optional filters and pagination.
|
|
92
|
+
GET /v1/project?status=...&userId=...&orgId=...&page=...&limit=...
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
status: Optional project status filter (e.g., "published").
|
|
96
|
+
user_id: Optional user filter.
|
|
97
|
+
org_id: Optional organization filter.
|
|
98
|
+
page: Optional page number (int).
|
|
99
|
+
limit: Optional page size (int).
|
|
100
|
+
"""
|
|
101
|
+
params: Dict[str, Any] = {}
|
|
102
|
+
if status is not None:
|
|
103
|
+
params["status"] = status
|
|
104
|
+
if user_id is not None:
|
|
105
|
+
params["userId"] = user_id
|
|
106
|
+
if org_id is not None:
|
|
107
|
+
params["orgId"] = org_id
|
|
108
|
+
if page is not None:
|
|
109
|
+
params["page"] = page
|
|
110
|
+
if limit is not None:
|
|
111
|
+
params["limit"] = limit
|
|
112
|
+
|
|
113
|
+
return self.http.request("GET", "/v1/project", params=params)
|
|
114
|
+
|
|
26
115
|
def get(self, project_id: str):
|
|
27
116
|
return self.http.request("GET", f"/v1/project/{project_id}")
|
|
28
117
|
|
|
29
|
-
|
|
30
|
-
|
|
118
|
+
class ProjectUpdateBody(TypedDict):
|
|
119
|
+
orgId: str
|
|
120
|
+
projectName: str
|
|
121
|
+
description: str
|
|
122
|
+
coworker_role: str
|
|
123
|
+
|
|
124
|
+
def update(self, project_id: str, body: ProjectUpdateBody):
|
|
125
|
+
"""Update a project via PUT /v1/project?projectId=... with required fields.
|
|
126
|
+
|
|
127
|
+
Required body keys: orgId, projectName, description, coworker_role
|
|
128
|
+
"""
|
|
129
|
+
params = {"projectId": project_id}
|
|
130
|
+
return self.http.request("PUT", "/v1/project", params=params, json=body)
|
|
31
131
|
|
|
32
132
|
def delete(self, project_id: str):
|
|
33
133
|
return self.http.request("DELETE", f"/v1/project/{project_id}")
|
wexa_sdk/skills.py
CHANGED
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional, TypedDict, Dict, Any
|
|
3
3
|
|
|
4
4
|
from .core.http import HttpClient
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
class SkillCreateBody(TypedDict):
|
|
8
|
+
"""Body for creating a Skill.
|
|
9
|
+
|
|
10
|
+
Required (user_id can be null but key is required):
|
|
11
|
+
- name: str
|
|
12
|
+
- logo: str
|
|
13
|
+
- connector_name: str
|
|
14
|
+
- description: str
|
|
15
|
+
- projectID: str
|
|
16
|
+
- connector_id: str
|
|
17
|
+
- user_id: Optional[str]
|
|
18
|
+
"""
|
|
19
|
+
name: str
|
|
20
|
+
logo: str
|
|
21
|
+
connector_name: str
|
|
22
|
+
description: str
|
|
23
|
+
projectID: str
|
|
24
|
+
connector_id: str
|
|
25
|
+
user_id: Optional[str]
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
class Skills:
|
|
7
29
|
def __init__(self, http: HttpClient):
|
|
8
30
|
self.http = http
|
|
9
31
|
|
|
10
32
|
# POST /skills/
|
|
11
|
-
def create(self, body:
|
|
33
|
+
def create(self, body: SkillCreateBody):
|
|
12
34
|
return self.http.request("POST", "/skills/", json=body)
|
|
13
35
|
|
|
14
36
|
# GET /skills/?projectID=...&limit=...
|
|
15
37
|
def list(self, project_id: str, *, limit: Optional[int] = None):
|
|
16
|
-
params
|
|
38
|
+
params = {"projectID": project_id}
|
|
17
39
|
if limit is not None:
|
|
18
40
|
params["limit"] = limit
|
|
19
41
|
return self.http.request("GET", "/skills/", params=params)
|
wexa_sdk/tables.py
CHANGED
|
@@ -1,14 +1,70 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Any, Optional
|
|
2
|
+
from typing import Any, Optional, TypedDict, List, Dict, Union
|
|
3
3
|
|
|
4
4
|
from .core.http import HttpClient
|
|
5
5
|
|
|
6
|
+
class ObjectField(TypedDict, total=False):
|
|
7
|
+
"""Field descriptor for object-type columns."""
|
|
8
|
+
key: str
|
|
9
|
+
keyType: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AgentflowTrigger(TypedDict, total=False):
|
|
13
|
+
"""Trigger configuration attached to a table or column.
|
|
14
|
+
|
|
15
|
+
Note: exact schemas for `condition` and `filters` may evolve; we leave them open.
|
|
16
|
+
"""
|
|
17
|
+
_id: str
|
|
18
|
+
id: str
|
|
19
|
+
condition: Dict[str, Any]
|
|
20
|
+
name: Optional[str]
|
|
21
|
+
goal: str
|
|
22
|
+
agentflow_id: Optional[str]
|
|
23
|
+
filters: List[Dict[str, Any]]
|
|
24
|
+
schedule_time: Optional[str]
|
|
25
|
+
event: str
|
|
26
|
+
start_from_agent_id: Optional[str]
|
|
27
|
+
trigger_type: str # e.g. "coworker"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Column(TypedDict, total=False):
|
|
31
|
+
"""Column definition for a table."""
|
|
32
|
+
column_name: str
|
|
33
|
+
column_type: str
|
|
34
|
+
column_id: str
|
|
35
|
+
array_type: Optional[str]
|
|
36
|
+
default_value: Union[Any, List[Any], Dict[str, Any]]
|
|
37
|
+
object_fields: List[ObjectField]
|
|
38
|
+
triggers: List[AgentflowTrigger]
|
|
39
|
+
enum_options: List[str]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CreateTableInput(TypedDict, total=False):
|
|
43
|
+
"""Typed input for creating a table.
|
|
44
|
+
|
|
45
|
+
Required keys: projectID, table_name
|
|
46
|
+
Optional keys: columns, triggers
|
|
47
|
+
"""
|
|
48
|
+
projectID: str
|
|
49
|
+
table_name: str
|
|
50
|
+
columns: List[Column]
|
|
51
|
+
triggers: List[AgentflowTrigger]
|
|
52
|
+
|
|
53
|
+
|
|
6
54
|
class Tables:
|
|
7
55
|
def __init__(self, http: HttpClient):
|
|
8
56
|
self.http = http
|
|
9
57
|
|
|
10
58
|
# Tables
|
|
11
|
-
def create_table(self, project_id: str, spec:
|
|
59
|
+
def create_table(self, project_id: str, spec: CreateTableInput):
|
|
60
|
+
"""Create a new table.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
project_id: The project ID (placed into query as `projectID`).
|
|
64
|
+
spec: Table specification containing at least `table_name`.
|
|
65
|
+
|
|
66
|
+
The backend expects `projectID` in both query params and JSON body.
|
|
67
|
+
"""
|
|
12
68
|
# API expects projectID as query param and in body with 'projectID' casing
|
|
13
69
|
params = {"projectID": project_id}
|
|
14
70
|
body = {"projectID": project_id, **spec}
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
wexa_sdk/__init__.py,sha256=dNvZ0fU4v0clBOuZWdd02SLxVfrBF2Ig-efQMOweq-I,1627
|
|
2
|
-
wexa_sdk/agentflows.py,sha256=
|
|
2
|
+
wexa_sdk/agentflows.py,sha256=G6F0TLTiSYFC0b9vJhHl-uClOhE9nXGjDENmiTz99FU,4351
|
|
3
3
|
wexa_sdk/analytics.py,sha256=PVWvRvuyxOAbwxxAoILquESyb2Jw3cJGogbBu2ATRH4,345
|
|
4
4
|
wexa_sdk/connectors_mgmt.py,sha256=7vCT4ilez2YjZnfFEzb0raglTwweqxomqtJOb36RVT4,2229
|
|
5
5
|
wexa_sdk/executions.py,sha256=-bVXo7ESA8AYZtc-tPDi28qWKJg_eYEQCo1kSYgE1P8,2509
|
|
6
|
-
wexa_sdk/files.py,sha256=
|
|
6
|
+
wexa_sdk/files.py,sha256=K2m6gxs_8XDhlW4W08DhSc-HwrMx3r2S5dOFvltLTqc,1235
|
|
7
7
|
wexa_sdk/inbox.py,sha256=aKFmST2FX09mDYXyrqNpUYTsq6z0iJG4qtsCeMWKPdo,1957
|
|
8
8
|
wexa_sdk/marketplace.py,sha256=jhpeSWLU_BLFJcbwx_vcLeUff3UEPkylyhVIm_Fcb5Y,1609
|
|
9
9
|
wexa_sdk/project_members.py,sha256=TssDroghwYMsPRibZ1dNvKynzMtgIUN1TDFsmc2AuW4,514
|
|
10
|
-
wexa_sdk/projects.py,sha256=
|
|
10
|
+
wexa_sdk/projects.py,sha256=RkatvCK-IdBXk5pc71HAkCi08p04ez_04nBbsMMpogs,4031
|
|
11
11
|
wexa_sdk/settings.py,sha256=TDnqYeFBvrrj9kznTUTJxG29sJ02bHxBlqE55DgIfTg,290
|
|
12
|
-
wexa_sdk/skills.py,sha256=
|
|
13
|
-
wexa_sdk/tables.py,sha256=
|
|
12
|
+
wexa_sdk/skills.py,sha256=ZOFdspJsns_X88nBMrhaFWWcTKuh5afk0hK73-Qzs9M,1799
|
|
13
|
+
wexa_sdk/tables.py,sha256=nS2QMePJEkEC-VzrIIZLmf8LruqD83PfjyDHif5vEZE,4307
|
|
14
14
|
wexa_sdk/tasks.py,sha256=YRXMxQwgpiflAxyUqedyo4LB6bsO7zsiM5uP0uE8_Ds,1349
|
|
15
15
|
wexa_sdk/connectors/__init__.py,sha256=eEtSQ8oXlYnoD3CUxPCF3Il6bgGyN6zfKI3_Pu41jXo,51
|
|
16
|
-
wexa_sdk/connectors/core.py,sha256=
|
|
16
|
+
wexa_sdk/connectors/core.py,sha256=7ghbFAPR1emgBL9PWStDp6AgZ5JDkiBWXQGaZ0B5Fek,1978
|
|
17
17
|
wexa_sdk/connectors/google_drive.py,sha256=Dibfoy8uKcGygmjCnrolPhKq5Fy5ye5-ee_kI4XD7kY,945
|
|
18
|
+
wexa_sdk/core/__init__.py,sha256=K-bUeDdR3iblN9BNwMQ-ZMbOcAJSAUkNwuoVz5L3fC4,39
|
|
19
|
+
wexa_sdk/core/http.py,sha256=4O59C5VlVhxaQNkjJ0UpARZk3g-rEoOxEbwE0u9NWbY,3721
|
|
18
20
|
wexa_sdk/models/__init__.py,sha256=yxQUjah8RTJh531y8QQXEeh5dp0d5k55dsrVvR4O1N8,75
|
|
19
|
-
wexa_sdk-0.1.
|
|
20
|
-
wexa_sdk-0.1.
|
|
21
|
-
wexa_sdk-0.1.
|
|
22
|
-
wexa_sdk-0.1.
|
|
21
|
+
wexa_sdk-0.1.6.dist-info/METADATA,sha256=Jux9cTUOZgJbd2TNMREAyVwev-v8-k29eV1Kvs-JgJA,581
|
|
22
|
+
wexa_sdk-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
wexa_sdk-0.1.6.dist-info/top_level.txt,sha256=iXL6c0Kro-mkIoNbjT76txRuoilWB-P7AHhmvKtdXkA,9
|
|
24
|
+
wexa_sdk-0.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|