wexa-sdk 0.1.3__tar.gz
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-0.1.3/PKG-INFO +23 -0
- wexa_sdk-0.1.3/README.md +7 -0
- wexa_sdk-0.1.3/pyproject.toml +29 -0
- wexa_sdk-0.1.3/setup.cfg +4 -0
- wexa_sdk-0.1.3/tests/test_agentflows.py +22 -0
- wexa_sdk-0.1.3/tests/test_agentflows_crud.py +23 -0
- wexa_sdk-0.1.3/tests/test_analytics.py +21 -0
- wexa_sdk-0.1.3/tests/test_connectors_core.py +45 -0
- wexa_sdk-0.1.3/tests/test_connectors_mgmt.py +44 -0
- wexa_sdk-0.1.3/tests/test_demo_coworker_workflow.py +68 -0
- wexa_sdk-0.1.3/tests/test_executions.py +23 -0
- wexa_sdk-0.1.3/tests/test_files.py +20 -0
- wexa_sdk-0.1.3/tests/test_inbox.py +28 -0
- wexa_sdk-0.1.3/tests/test_integration_agentflows_create.py +40 -0
- wexa_sdk-0.1.3/tests/test_integration_marketplace.py +13 -0
- wexa_sdk-0.1.3/tests/test_marketplace.py +24 -0
- wexa_sdk-0.1.3/tests/test_project_members.py +18 -0
- wexa_sdk-0.1.3/tests/test_projects.py +22 -0
- wexa_sdk-0.1.3/tests/test_projects_crud.py +24 -0
- wexa_sdk-0.1.3/tests/test_projects_get_all.py +42 -0
- wexa_sdk-0.1.3/tests/test_settings.py +19 -0
- wexa_sdk-0.1.3/tests/test_skills.py +24 -0
- wexa_sdk-0.1.3/tests/test_tables.py +49 -0
- wexa_sdk-0.1.3/tests/test_tasks.py +24 -0
- wexa_sdk-0.1.3/wexa_sdk/__init__.py +37 -0
- wexa_sdk-0.1.3/wexa_sdk/agentflows.py +75 -0
- wexa_sdk-0.1.3/wexa_sdk/analytics.py +12 -0
- wexa_sdk-0.1.3/wexa_sdk/connectors/__init__.py +1 -0
- wexa_sdk-0.1.3/wexa_sdk/connectors/core.py +24 -0
- wexa_sdk-0.1.3/wexa_sdk/connectors/google_drive.py +22 -0
- wexa_sdk-0.1.3/wexa_sdk/connectors_mgmt.py +47 -0
- wexa_sdk-0.1.3/wexa_sdk/core/__init__.py +1 -0
- wexa_sdk-0.1.3/wexa_sdk/core/http.py +86 -0
- wexa_sdk-0.1.3/wexa_sdk/executions.py +57 -0
- wexa_sdk-0.1.3/wexa_sdk/files.py +30 -0
- wexa_sdk-0.1.3/wexa_sdk/inbox.py +41 -0
- wexa_sdk-0.1.3/wexa_sdk/marketplace.py +31 -0
- wexa_sdk-0.1.3/wexa_sdk/models/__init__.py +1 -0
- wexa_sdk-0.1.3/wexa_sdk/project_members.py +16 -0
- wexa_sdk-0.1.3/wexa_sdk/projects.py +134 -0
- wexa_sdk-0.1.3/wexa_sdk/settings.py +11 -0
- wexa_sdk-0.1.3/wexa_sdk/skills.py +57 -0
- wexa_sdk-0.1.3/wexa_sdk/tables.py +59 -0
- wexa_sdk-0.1.3/wexa_sdk/tasks.py +36 -0
- wexa_sdk-0.1.3/wexa_sdk.egg-info/PKG-INFO +23 -0
- wexa_sdk-0.1.3/wexa_sdk.egg-info/SOURCES.txt +47 -0
- wexa_sdk-0.1.3/wexa_sdk.egg-info/dependency_links.txt +1 -0
- wexa_sdk-0.1.3/wexa_sdk.egg-info/requires.txt +2 -0
- wexa_sdk-0.1.3/wexa_sdk.egg-info/top_level.txt +1 -0
wexa_sdk-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wexa-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Official Wexa Python SDK
|
|
5
|
+
Author: Wexa
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/wexa-ai/wexa-sdk
|
|
8
|
+
Keywords: wexa,sdk,api
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: httpx>=0.27
|
|
15
|
+
Requires-Dist: pydantic>=2.6
|
|
16
|
+
|
|
17
|
+
# wexa-sdk (Python)
|
|
18
|
+
|
|
19
|
+
Python SDK for Wexa API.
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from wexa_sdk import WexaClient
|
|
23
|
+
```
|
wexa_sdk-0.1.3/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wexa-sdk"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "Official Wexa Python SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
keywords = ["wexa", "sdk", "api"]
|
|
13
|
+
authors = [{ name = "Wexa" }]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"httpx>=0.27",
|
|
21
|
+
"pydantic>=2.6",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/wexa-ai/wexa-sdk"
|
|
26
|
+
|
|
27
|
+
[tool.setuptools]
|
|
28
|
+
packages = ["wexa_sdk", "wexa_sdk.core", "wexa_sdk.connectors", "wexa_sdk.models"]
|
|
29
|
+
include-package-data = true
|
wexa_sdk-0.1.3/setup.cfg
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from wexa_sdk import WexaClient
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_agentflows_list_builds_params(monkeypatch):
|
|
6
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
7
|
+
calls = {}
|
|
8
|
+
|
|
9
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
10
|
+
calls["method"] = method
|
|
11
|
+
calls["path"] = path
|
|
12
|
+
calls["params"] = params
|
|
13
|
+
return {"ok": True}
|
|
14
|
+
|
|
15
|
+
c.http.request = fake_request # type: ignore
|
|
16
|
+
|
|
17
|
+
res = c.agentflows.list(projectID="p1", skip=1, limit=2)
|
|
18
|
+
|
|
19
|
+
assert calls["method"] == "GET"
|
|
20
|
+
assert calls["path"] == "/agentflows"
|
|
21
|
+
assert calls["params"] == {"projectID": "p1", "skip": 1, "limit": 2}
|
|
22
|
+
assert res == {"ok": True}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_agentflows_crud(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
# create with projectID in body -> should go to query as well
|
|
15
|
+
c.agentflows.create({"name": "N", "projectID": "p1"})
|
|
16
|
+
# update
|
|
17
|
+
c.agentflows.update("af1", {"name": "U"})
|
|
18
|
+
# delete
|
|
19
|
+
c.agentflows.delete("p1", "af1")
|
|
20
|
+
|
|
21
|
+
assert calls[0][0] == "POST" and calls[0][1] == "/agentflow/" and calls[0][2] == {"projectID": "p1"}
|
|
22
|
+
assert calls[1][0] == "PUT" and calls[1][1] == "/agentflow/af1"
|
|
23
|
+
assert calls[2][0] == "DELETE" and calls[2][1] == "/agentflow/p1/af1"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_analytics_get_builds_query(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = {}
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls["method"] = method
|
|
10
|
+
calls["path"] = path
|
|
11
|
+
calls["params"] = params
|
|
12
|
+
return {"ok": True}
|
|
13
|
+
|
|
14
|
+
c.http.request = fake_request # type: ignore
|
|
15
|
+
|
|
16
|
+
res = c.analytics.get("p1")
|
|
17
|
+
|
|
18
|
+
assert calls["method"] == "GET"
|
|
19
|
+
assert calls["path"] == "/analytics"
|
|
20
|
+
assert calls["params"] == {"projectID": "p1"}
|
|
21
|
+
assert res == {"ok": True}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_connectors_core_actions_and_config(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
# action without connector_id, then with connector_id
|
|
15
|
+
c.connectors.action("drive", "sync", body={"x": 1}, projectID="p1")
|
|
16
|
+
c.connectors.action("drive", "sync", "cid1", body={"y": 2}, projectID="p1")
|
|
17
|
+
|
|
18
|
+
# config
|
|
19
|
+
c.connectors.set_config("drive", "p1", {"cfg": True})
|
|
20
|
+
c.connectors.get_config("drive", "p1")
|
|
21
|
+
|
|
22
|
+
assert calls[0] == (
|
|
23
|
+
"POST",
|
|
24
|
+
"/actions/drive/sync",
|
|
25
|
+
{"projectID": "p1"},
|
|
26
|
+
{"x": 1},
|
|
27
|
+
)
|
|
28
|
+
assert calls[1] == (
|
|
29
|
+
"POST",
|
|
30
|
+
"/actions/drive/sync/cid1",
|
|
31
|
+
{"projectID": "p1"},
|
|
32
|
+
{"y": 2},
|
|
33
|
+
)
|
|
34
|
+
assert calls[2] == (
|
|
35
|
+
"POST",
|
|
36
|
+
"/actions/drive/config",
|
|
37
|
+
{"projectID": "p1"},
|
|
38
|
+
{"cfg": True},
|
|
39
|
+
)
|
|
40
|
+
assert calls[3] == (
|
|
41
|
+
"GET",
|
|
42
|
+
"/actions/drive/config/p1",
|
|
43
|
+
None,
|
|
44
|
+
None,
|
|
45
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_connectors_mgmt_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
# list variants
|
|
15
|
+
c.connectors_mgmt.list()
|
|
16
|
+
c.connectors_mgmt.list("p1")
|
|
17
|
+
c.connectors_mgmt.list_by_project_id("p1")
|
|
18
|
+
|
|
19
|
+
# get
|
|
20
|
+
c.connectors_mgmt.get_by_id("cid1")
|
|
21
|
+
c.connectors_mgmt.get_by_id_path("cid1")
|
|
22
|
+
|
|
23
|
+
# delete variants
|
|
24
|
+
c.connectors_mgmt.delete("cid1")
|
|
25
|
+
c.connectors_mgmt.delete("cid1", project_id="p1")
|
|
26
|
+
c.connectors_mgmt.delete_by_id_path("cid1", project_id="p1")
|
|
27
|
+
|
|
28
|
+
# status + triggers
|
|
29
|
+
c.connectors_mgmt.update_status(new_status="active", connectorID="cid1", data_loader_config={})
|
|
30
|
+
c.connectors_mgmt.list_trigger_actions("p1")
|
|
31
|
+
c.connectors_mgmt.list_trigger_actions_by_project("p1")
|
|
32
|
+
|
|
33
|
+
i = 0
|
|
34
|
+
assert calls[i] == ("GET", "/connectors/", None, None); i += 1
|
|
35
|
+
assert calls[i] == ("GET", "/connectors/", {"projectID": "p1"}, None); i += 1
|
|
36
|
+
assert calls[i] == ("GET", "/connectors/p1", None, None); i += 1
|
|
37
|
+
assert calls[i] == ("GET", "/v1/connector/cid1", None, None); i += 1
|
|
38
|
+
assert calls[i] == ("GET", "/connector/cid1", None, None); i += 1
|
|
39
|
+
assert calls[i] == ("DELETE", "/v1/connector/cid1", None, None); i += 1
|
|
40
|
+
assert calls[i] == ("DELETE", "/v1/connector/cid1", {"projectID": "p1"}, None); i += 1
|
|
41
|
+
assert calls[i] == ("DELETE", "/connector/cid1", {"projectID": "p1"}, None); i += 1
|
|
42
|
+
assert calls[i] == ("POST", "/connectors/change_status", None, {"new_status": "active", "connectorID": "cid1", "data_loader_config": {}}); i += 1
|
|
43
|
+
assert calls[i] == ("GET", "/connectors/trigger_actions", {"projectID": "p1"}, None); i += 1
|
|
44
|
+
assert calls[i] == ("GET", "/connectors/p1/trigger_actions", {"projectID": "p1"}, None); i += 1
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import json
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from wexa_sdk import WexaClient
|
|
7
|
+
|
|
8
|
+
BASE = os.environ.get("WEXA_BASE_URL", "https://api.wexa.ai")
|
|
9
|
+
API_KEY = os.environ.get("WEXA_API_KEY")
|
|
10
|
+
PROJECT_ID = os.environ.get("WEXA_PROJECT_ID", "69088bf4121a635f1301ad8c")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.skipif(not API_KEY, reason="Set WEXA_API_KEY to run this integration test")
|
|
14
|
+
def test_coworker_create_or_load_and_execute():
|
|
15
|
+
c = WexaClient(base_url=BASE, api_key=API_KEY)
|
|
16
|
+
# Use a mostly-unique name per run to avoid conflicts
|
|
17
|
+
name = f"InvoiceProcessor-{int(time.time()) % 100000}"
|
|
18
|
+
|
|
19
|
+
def get_by_name(name: str, project_id: str):
|
|
20
|
+
skip, limit = 0, 100
|
|
21
|
+
while True:
|
|
22
|
+
# Some environments reject skip=0; omit skip on first page
|
|
23
|
+
if skip > 0:
|
|
24
|
+
page = c.agentflows.list(projectID=project_id, skip=skip, limit=limit) or {}
|
|
25
|
+
else:
|
|
26
|
+
page = c.agentflows.list(projectID=project_id, limit=limit) or {}
|
|
27
|
+
arr = page.get("agentflows") or page.get("data") or []
|
|
28
|
+
for af in arr:
|
|
29
|
+
if af.get("name") == name:
|
|
30
|
+
return af
|
|
31
|
+
if len(arr) < limit:
|
|
32
|
+
return None
|
|
33
|
+
skip += limit
|
|
34
|
+
|
|
35
|
+
af = get_by_name(name, PROJECT_ID)
|
|
36
|
+
if not af:
|
|
37
|
+
body = {
|
|
38
|
+
"name": name,
|
|
39
|
+
"description": "created via SDK test",
|
|
40
|
+
"role": "SDK_ROLE",
|
|
41
|
+
"projectID": PROJECT_ID,
|
|
42
|
+
}
|
|
43
|
+
af = c.agentflows.create(body, projectID=PROJECT_ID)
|
|
44
|
+
assert af and af.get("_id"), "Agentflow creation failed"
|
|
45
|
+
|
|
46
|
+
# Execute the flow
|
|
47
|
+
payload = {
|
|
48
|
+
"agentflow_id": af["_id"],
|
|
49
|
+
"executed_by": "sdk@test",
|
|
50
|
+
"goal": "Demo run",
|
|
51
|
+
"input_variables": {"echo": "hello"},
|
|
52
|
+
"projectID": PROJECT_ID,
|
|
53
|
+
}
|
|
54
|
+
started = c.executions.start(payload, projectID=PROJECT_ID)
|
|
55
|
+
assert started and started.get("_id"), "Execution start failed"
|
|
56
|
+
|
|
57
|
+
# Try a brief wait; if it times out, fetch current state and finish
|
|
58
|
+
try:
|
|
59
|
+
res = c.executions.wait(started["_id"], timeout_ms=15_000)
|
|
60
|
+
except Exception:
|
|
61
|
+
res = c.executions.get(started["_id"])
|
|
62
|
+
|
|
63
|
+
assert isinstance(res, dict)
|
|
64
|
+
# Print (visible in CI logs) for manual inspection if needed
|
|
65
|
+
print(json.dumps({
|
|
66
|
+
"agentflow": {"_id": af.get("_id"), "name": af.get("name")},
|
|
67
|
+
"execution": {"_id": started.get("_id"), "status": res.get("status")}
|
|
68
|
+
})[:1000])
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_executions_start_posts_payload_and_query(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = {}
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls["method"] = method
|
|
10
|
+
calls["path"] = path
|
|
11
|
+
calls["params"] = params
|
|
12
|
+
calls["json"] = json
|
|
13
|
+
return {"execution_id": "e1"}
|
|
14
|
+
|
|
15
|
+
c.http.request = fake_request # type: ignore
|
|
16
|
+
|
|
17
|
+
res = c.executions.start({"agentflow_id": "a1", "inputs": {}}, projectID="p1")
|
|
18
|
+
|
|
19
|
+
assert calls["method"] == "POST"
|
|
20
|
+
assert calls["path"] == "/execute_flow"
|
|
21
|
+
assert calls["params"] == {"projectID": "p1"}
|
|
22
|
+
assert calls["json"] == {"agentflow_id": "a1", "inputs": {}}
|
|
23
|
+
assert res == {"execution_id": "e1"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_files_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.files.upload_request("proj", "bucket", {"filenames": ["a.txt"]})
|
|
15
|
+
c.files.get_by_file_id("file1", "proj")
|
|
16
|
+
c.files.list_by_connector("conn1")
|
|
17
|
+
|
|
18
|
+
assert calls[0][0] == "POST" and calls[0][1] == "/files/upload" and calls[0][2] == {"projectID": "proj", "container_name": "bucket"}
|
|
19
|
+
assert calls[1][0] == "GET" and calls[1][1] == "/file/file1/" and calls[1][2] == {"projectID": "proj"}
|
|
20
|
+
assert calls[2][0] == "GET" and calls[2][1] == "/files/conn1/connector/"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_inbox_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.inbox.create({"x": 1})
|
|
15
|
+
c.inbox.list("p1", limit=2)
|
|
16
|
+
c.inbox.update_runtime("p1", {"a": 1})
|
|
17
|
+
c.inbox.update_anomaly("p1", {"b": 2})
|
|
18
|
+
c.inbox.update_preview("p1", {"c": 3})
|
|
19
|
+
c.inbox.update_preview_by_execution("exec1", {"d": 4}, "p1")
|
|
20
|
+
c.inbox.get("inb1", "p1")
|
|
21
|
+
|
|
22
|
+
assert calls[0] == ("POST", "/inbox/create", None, {"x": 1})
|
|
23
|
+
assert calls[1] == ("GET", "/inbox", {"projectID": "p1", "limit": 2}, None)
|
|
24
|
+
assert calls[2] == ("POST", "/inbox/update/runtime_input/", {"projectID": "p1"}, {"a": 1})
|
|
25
|
+
assert calls[3] == ("POST", "/inbox/update/anomaly_detection/", {"projectID": "p1"}, {"b": 2})
|
|
26
|
+
assert calls[4] == ("POST", "/inbox/update/preview/", {"projectID": "p1"}, {"c": 3})
|
|
27
|
+
assert calls[5] == ("POST", "/inbox/update/preview/exec1", {"projectID": "p1"}, {"d": 4})
|
|
28
|
+
assert calls[6] == ("GET", "/inbox/inb1", {"projectID": "p1"}, None)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import os, time, json, pytest
|
|
2
|
+
from wexa_sdk import WexaClient
|
|
3
|
+
from wexa_sdk.core.http import ApiError
|
|
4
|
+
|
|
5
|
+
missing_env = not (os.getenv("WEXA_BASE_URL") and os.getenv("WEXA_API_KEY") and os.getenv("PROJECT_ID"))
|
|
6
|
+
|
|
7
|
+
@pytest.mark.integration
|
|
8
|
+
@pytest.mark.skipif(missing_env, reason="WEXA_BASE_URL/WEXA_API_KEY/PROJECT_ID not set")
|
|
9
|
+
def test_agentflows_create_get_delete():
|
|
10
|
+
base = os.environ["WEXA_BASE_URL"]
|
|
11
|
+
key = os.environ["WEXA_API_KEY"]
|
|
12
|
+
pid = os.environ["PROJECT_ID"]
|
|
13
|
+
|
|
14
|
+
c = WexaClient(base_url=base, api_key=key)
|
|
15
|
+
|
|
16
|
+
body = {
|
|
17
|
+
"name": f"sdk-integ-py-{int(time.time())}",
|
|
18
|
+
"description": "integration-create via sdk",
|
|
19
|
+
"role": "SDK_ROLE",
|
|
20
|
+
"projectID": pid,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
afid = None
|
|
24
|
+
try:
|
|
25
|
+
created = c.agentflows.create(body, projectID=pid)
|
|
26
|
+
assert isinstance(created, dict)
|
|
27
|
+
afid = created.get("_id") or created.get("id")
|
|
28
|
+
assert afid and isinstance(afid, str)
|
|
29
|
+
|
|
30
|
+
got = c.agentflows.get(afid)
|
|
31
|
+
assert got.get("_id") == afid
|
|
32
|
+
assert got.get("name") == body["name"]
|
|
33
|
+
except ApiError as e:
|
|
34
|
+
pytest.fail(f"API error: {e.status} {e.detail}")
|
|
35
|
+
finally:
|
|
36
|
+
if afid:
|
|
37
|
+
try:
|
|
38
|
+
c.agentflows.delete(pid, afid)
|
|
39
|
+
except ApiError:
|
|
40
|
+
pass
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pytest
|
|
3
|
+
from wexa_sdk import WexaClient
|
|
4
|
+
|
|
5
|
+
pytestmark = pytest.mark.integration
|
|
6
|
+
|
|
7
|
+
missing_env = not os.getenv("WEXA_BASE_URL") or not os.getenv("WEXA_API_KEY")
|
|
8
|
+
|
|
9
|
+
@pytest.mark.skipif(missing_env, reason="WEXA_BASE_URL/WEXA_API_KEY not set")
|
|
10
|
+
def test_marketplace_lists_coworkers():
|
|
11
|
+
c = WexaClient(base_url=os.environ["WEXA_BASE_URL"], api_key=os.environ["WEXA_API_KEY"])
|
|
12
|
+
res = c.marketplace.list_coworkers(search_key="", limit=1)
|
|
13
|
+
assert isinstance(res, dict)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_marketplace_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.marketplace.list_connectors(search_key="", projectID="p1", filter_type="ALL")
|
|
15
|
+
c.marketplace.list_coworkers(search_key="", limit=2)
|
|
16
|
+
c.marketplace.get_coworker_by_id("cw1")
|
|
17
|
+
c.marketplace.purchase_coworker("cw1", organization_id="org1", body={"plan": "pro"})
|
|
18
|
+
c.marketplace.check_coworker_update("cw1")
|
|
19
|
+
|
|
20
|
+
assert calls[0] == ("GET", "/public/connectors/all", {"search_key": "", "projectID": "p1", "filter_type": "ALL"}, None)
|
|
21
|
+
assert calls[1] == ("GET", "/public/marketplace/coworkers", {"search_key": "", "limit": 2}, None)
|
|
22
|
+
assert calls[2] == ("GET", "/public/marketplace/coworker/cw1", None, None)
|
|
23
|
+
assert calls[3] == ("POST", "/marketplace/coworker/cw1/purchase", {"organization_id": "org1"}, {"plan": "pro"})
|
|
24
|
+
assert calls[4] == ("GET", "/marketplace/coworker/update/cw1/check", None, None)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_project_members_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.project_members.summary("p1")
|
|
15
|
+
c.project_members.list("p1")
|
|
16
|
+
|
|
17
|
+
assert calls[0] == ("GET", "/project-member/p1/summary", None, None)
|
|
18
|
+
assert calls[1] == ("GET", "/project-member/p1", None, None)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_projects_create_posts_body(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = {}
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls["method"] = method
|
|
10
|
+
calls["path"] = path
|
|
11
|
+
calls["json"] = json
|
|
12
|
+
return {"_id": "p1"}
|
|
13
|
+
|
|
14
|
+
c.http.request = fake_request # type: ignore
|
|
15
|
+
|
|
16
|
+
body = {"orgId": "o1", "projectName": "Test", "description": "d", "coworker_role": "r"}
|
|
17
|
+
res = c.projects.create(body)
|
|
18
|
+
|
|
19
|
+
assert calls["method"] == "POST"
|
|
20
|
+
assert calls["path"] == "/v1/project"
|
|
21
|
+
assert calls["json"] == body
|
|
22
|
+
assert res == {"_id": "p1"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_projects_crud_paths(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.projects.create({"orgId": "o1", "projectName": "P"})
|
|
15
|
+
c.projects.list()
|
|
16
|
+
c.projects.get("p1")
|
|
17
|
+
c.projects.update("p1", {"description": "d"})
|
|
18
|
+
c.projects.delete("p1")
|
|
19
|
+
|
|
20
|
+
assert calls[0][0] == "POST" and calls[0][1] == "/v1/project"
|
|
21
|
+
assert calls[1][0] == "GET" and calls[1][1] == "/v1/project"
|
|
22
|
+
assert calls[2][0] == "GET" and calls[2][1] == "/v1/project/p1"
|
|
23
|
+
assert calls[3][0] == "PUT" and calls[3][1] == "/v1/project/p1"
|
|
24
|
+
assert calls[4][0] == "DELETE" and calls[4][1] == "/v1/project/p1"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from wexa_sdk import WexaClient
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_projects_get_all_path_and_params(monkeypatch):
|
|
6
|
+
base_url = os.getenv("WEXA_BASE_URL", "https://api.wexa.ai")
|
|
7
|
+
api_key = os.getenv("WEXA_API_KEY", "key")
|
|
8
|
+
|
|
9
|
+
c = WexaClient(base_url=base_url, api_key=api_key)
|
|
10
|
+
calls = []
|
|
11
|
+
|
|
12
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
13
|
+
calls.append((method, path, params, json))
|
|
14
|
+
# Simulate API shape
|
|
15
|
+
return {"items": [], "count": 0}
|
|
16
|
+
|
|
17
|
+
# Patch HTTP layer to avoid real network
|
|
18
|
+
c.http.request = fake_request # type: ignore
|
|
19
|
+
|
|
20
|
+
res = c.projects.get_all(
|
|
21
|
+
status="published",
|
|
22
|
+
user_id="66f3cdde22bc63eb7490e23c",
|
|
23
|
+
org_id="66f3cdde22bc63eb7490e23e",
|
|
24
|
+
page=1,
|
|
25
|
+
limit=12,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Assert method and path
|
|
29
|
+
assert calls[0][0] == "GET"
|
|
30
|
+
assert calls[0][1] == "/v1/project" # versioned path
|
|
31
|
+
|
|
32
|
+
# Assert query params
|
|
33
|
+
assert calls[0][2] == {
|
|
34
|
+
"status": "published",
|
|
35
|
+
"userId": "66f3cdde22bc63eb7490e23c",
|
|
36
|
+
"orgId": "66f3cdde22bc63eb7490e23e",
|
|
37
|
+
"page": 1,
|
|
38
|
+
"limit": 12,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Assert returned structure from our fake
|
|
42
|
+
assert res == {"items": [], "count": 0}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_settings_get(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = {}
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls["method"] = method
|
|
10
|
+
calls["path"] = path
|
|
11
|
+
return {"ok": True}
|
|
12
|
+
|
|
13
|
+
c.http.request = fake_request # type: ignore
|
|
14
|
+
|
|
15
|
+
res = c.settings.get("p1")
|
|
16
|
+
|
|
17
|
+
assert calls["method"] == "GET"
|
|
18
|
+
assert calls["path"] == "/settings/p1"
|
|
19
|
+
assert res == {"ok": True}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from wexa_sdk import WexaClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_skills_endpoints(monkeypatch):
|
|
5
|
+
c = WexaClient(base_url="https://api.wexa.ai", api_key="key")
|
|
6
|
+
calls = []
|
|
7
|
+
|
|
8
|
+
def fake_request(method, path, *, params=None, json=None, headers=None): # type: ignore
|
|
9
|
+
calls.append((method, path, params, json))
|
|
10
|
+
return {"ok": True}
|
|
11
|
+
|
|
12
|
+
c.http.request = fake_request # type: ignore
|
|
13
|
+
|
|
14
|
+
c.skills.create({"name": "s1"})
|
|
15
|
+
c.skills.list("p1", limit=2)
|
|
16
|
+
c.skills.list_by_category("p1", "LLM", limit=1)
|
|
17
|
+
c.skills.get_by_id("sid1")
|
|
18
|
+
c.skills.get_by_name("s1", "p1")
|
|
19
|
+
|
|
20
|
+
assert calls[0] == ("POST", "/skills/", None, {"name": "s1"})
|
|
21
|
+
assert calls[1] == ("GET", "/skills/", {"projectID": "p1", "limit": 2}, None)
|
|
22
|
+
assert calls[2] == ("GET", "/skills/category", {"projectId": "p1", "category": "LLM", "limit": 1}, None)
|
|
23
|
+
assert calls[3] == ("GET", "/skills/sid1", None, None)
|
|
24
|
+
assert calls[4] == ("GET", "/skills/", {"name": "s1", "projectID": "p1"}, None)
|