modulex-python 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.
- modulex/__init__.py +39 -0
- modulex/_base.py +281 -0
- modulex/_client.py +237 -0
- modulex/_compat.py +39 -0
- modulex/_config.py +26 -0
- modulex/_exceptions.py +131 -0
- modulex/_streaming.py +118 -0
- modulex/py.typed +0 -0
- modulex/resources/__init__.py +1 -0
- modulex/resources/api_keys.py +39 -0
- modulex/resources/auth.py +38 -0
- modulex/resources/chats.py +62 -0
- modulex/resources/composer.py +134 -0
- modulex/resources/credentials.py +197 -0
- modulex/resources/dashboard.py +110 -0
- modulex/resources/deployments.py +92 -0
- modulex/resources/executions.py +97 -0
- modulex/resources/integrations.py +110 -0
- modulex/resources/knowledge.py +343 -0
- modulex/resources/notifications.py +39 -0
- modulex/resources/organizations.py +72 -0
- modulex/resources/schedules.py +172 -0
- modulex/resources/subscriptions.py +38 -0
- modulex/resources/system.py +28 -0
- modulex/resources/templates.py +115 -0
- modulex/resources/workflows.py +156 -0
- modulex/types/__init__.py +294 -0
- modulex/types/api_keys.py +19 -0
- modulex/types/auth.py +62 -0
- modulex/types/chats.py +55 -0
- modulex/types/composer.py +27 -0
- modulex/types/credentials.py +79 -0
- modulex/types/dashboard.py +54 -0
- modulex/types/executions.py +104 -0
- modulex/types/integrations.py +29 -0
- modulex/types/knowledge.py +75 -0
- modulex/types/notifications.py +16 -0
- modulex/types/organizations.py +43 -0
- modulex/types/schedules.py +48 -0
- modulex/types/shared.py +39 -0
- modulex/types/subscriptions.py +59 -0
- modulex/types/templates.py +50 -0
- modulex/types/workflows.py +253 -0
- modulex_python-0.1.0.dist-info/METADATA +435 -0
- modulex_python-0.1.0.dist-info/RECORD +47 -0
- modulex_python-0.1.0.dist-info/WHEEL +4 -0
- modulex_python-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Credentials resource for the ModuleX Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from modulex._base import _BaseResource
|
|
8
|
+
from modulex._streaming import EventSourceStream
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Credentials(_BaseResource):
|
|
12
|
+
"""Resource for managing integration credentials."""
|
|
13
|
+
|
|
14
|
+
async def list(
|
|
15
|
+
self,
|
|
16
|
+
*,
|
|
17
|
+
integration_name: str | None = None,
|
|
18
|
+
auth_type: str | None = None,
|
|
19
|
+
limit: int = 100,
|
|
20
|
+
offset: int = 0,
|
|
21
|
+
organization_id: str | None = None,
|
|
22
|
+
) -> Any:
|
|
23
|
+
"""Return a paginated list of credentials, optionally filtered by integration or auth type."""
|
|
24
|
+
params: dict[str, Any] = {"limit": limit, "offset": offset}
|
|
25
|
+
if integration_name is not None:
|
|
26
|
+
params["integration_name"] = integration_name
|
|
27
|
+
if auth_type is not None:
|
|
28
|
+
params["auth_type"] = auth_type
|
|
29
|
+
return await self._get("/credentials", params=params, organization_id=organization_id)
|
|
30
|
+
|
|
31
|
+
async def get(
|
|
32
|
+
self,
|
|
33
|
+
credential_id: str,
|
|
34
|
+
*,
|
|
35
|
+
include_masked: bool = False,
|
|
36
|
+
organization_id: str | None = None,
|
|
37
|
+
) -> Any:
|
|
38
|
+
"""Return a single credential by its ID, optionally including masked auth data."""
|
|
39
|
+
return await self._get(
|
|
40
|
+
f"/credentials/{credential_id}",
|
|
41
|
+
params={"include_masked": include_masked},
|
|
42
|
+
organization_id=organization_id,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def create(
|
|
46
|
+
self,
|
|
47
|
+
integration_name: str,
|
|
48
|
+
*,
|
|
49
|
+
auth_data: dict[str, Any] | None = None,
|
|
50
|
+
auth_type: str | None = None,
|
|
51
|
+
display_name: str | None = None,
|
|
52
|
+
metadata: dict[str, Any] | None = None,
|
|
53
|
+
make_default: bool = False,
|
|
54
|
+
expires_at: str | None = None,
|
|
55
|
+
organization_id: str | None = None,
|
|
56
|
+
) -> Any:
|
|
57
|
+
"""Create a new credential for the specified integration."""
|
|
58
|
+
body: dict[str, Any] = {
|
|
59
|
+
"integration_name": integration_name,
|
|
60
|
+
"make_default": make_default,
|
|
61
|
+
}
|
|
62
|
+
if auth_data is not None:
|
|
63
|
+
body["auth_data"] = auth_data
|
|
64
|
+
if auth_type is not None:
|
|
65
|
+
body["auth_type"] = auth_type
|
|
66
|
+
if display_name is not None:
|
|
67
|
+
body["display_name"] = display_name
|
|
68
|
+
if metadata is not None:
|
|
69
|
+
body["metadata"] = metadata
|
|
70
|
+
if expires_at is not None:
|
|
71
|
+
body["expires_at"] = expires_at
|
|
72
|
+
return await self._post("/credentials", json=body, organization_id=organization_id)
|
|
73
|
+
|
|
74
|
+
async def update(
|
|
75
|
+
self,
|
|
76
|
+
credential_id: str,
|
|
77
|
+
*,
|
|
78
|
+
display_name: str | None = None,
|
|
79
|
+
metadata: dict[str, Any] | None = None,
|
|
80
|
+
organization_id: str | None = None,
|
|
81
|
+
) -> Any:
|
|
82
|
+
"""Update the display name or metadata of an existing credential."""
|
|
83
|
+
body: dict[str, Any] = {}
|
|
84
|
+
if display_name is not None:
|
|
85
|
+
body["display_name"] = display_name
|
|
86
|
+
if metadata is not None:
|
|
87
|
+
body["metadata"] = metadata
|
|
88
|
+
return await self._put(
|
|
89
|
+
f"/credentials/{credential_id}",
|
|
90
|
+
json=body or None,
|
|
91
|
+
organization_id=organization_id,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
async def delete(self, credential_id: str, *, organization_id: str | None = None) -> None:
|
|
95
|
+
"""Permanently delete a credential by its ID."""
|
|
96
|
+
await self._delete(f"/credentials/{credential_id}", organization_id=organization_id)
|
|
97
|
+
|
|
98
|
+
async def set_default(self, credential_id: str, *, organization_id: str | None = None) -> Any:
|
|
99
|
+
"""Mark a credential as the default for its integration."""
|
|
100
|
+
return await self._post(
|
|
101
|
+
f"/credentials/{credential_id}/set-default",
|
|
102
|
+
organization_id=organization_id,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
async def test(self, credential_id: str, *, organization_id: str | None = None) -> Any:
|
|
106
|
+
"""Test an existing credential to verify it is still valid."""
|
|
107
|
+
return await self._post(f"/credentials/{credential_id}/test", organization_id=organization_id)
|
|
108
|
+
|
|
109
|
+
async def test_temporary(
|
|
110
|
+
self,
|
|
111
|
+
integration_name: str,
|
|
112
|
+
auth_type: str,
|
|
113
|
+
auth_data: dict[str, Any],
|
|
114
|
+
*,
|
|
115
|
+
organization_id: str | None = None,
|
|
116
|
+
) -> Any:
|
|
117
|
+
"""Test a set of credentials without persisting them."""
|
|
118
|
+
body: dict[str, Any] = {
|
|
119
|
+
"integration_name": integration_name,
|
|
120
|
+
"auth_type": auth_type,
|
|
121
|
+
"auth_data": auth_data,
|
|
122
|
+
}
|
|
123
|
+
return await self._post("/credentials/test-temporary", json=body, organization_id=organization_id)
|
|
124
|
+
|
|
125
|
+
async def usage(
|
|
126
|
+
self,
|
|
127
|
+
credential_id: str,
|
|
128
|
+
*,
|
|
129
|
+
start_date: str | None = None,
|
|
130
|
+
end_date: str | None = None,
|
|
131
|
+
organization_id: str | None = None,
|
|
132
|
+
) -> Any:
|
|
133
|
+
"""Return usage statistics for a credential within an optional date range."""
|
|
134
|
+
params: dict[str, Any] = {}
|
|
135
|
+
if start_date is not None:
|
|
136
|
+
params["start_date"] = start_date
|
|
137
|
+
if end_date is not None:
|
|
138
|
+
params["end_date"] = end_date
|
|
139
|
+
return await self._get(
|
|
140
|
+
f"/credentials/{credential_id}/usage",
|
|
141
|
+
params=params or None,
|
|
142
|
+
organization_id=organization_id,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
async def audit(
|
|
146
|
+
self,
|
|
147
|
+
credential_id: str,
|
|
148
|
+
*,
|
|
149
|
+
limit: int = 100,
|
|
150
|
+
offset: int = 0,
|
|
151
|
+
organization_id: str | None = None,
|
|
152
|
+
) -> Any:
|
|
153
|
+
"""Return the audit log for a credential."""
|
|
154
|
+
return await self._get(
|
|
155
|
+
f"/credentials/{credential_id}/audit",
|
|
156
|
+
params={"limit": limit, "offset": offset},
|
|
157
|
+
organization_id=organization_id,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
async def create_mcp_server(
|
|
161
|
+
self,
|
|
162
|
+
server_url: str,
|
|
163
|
+
*,
|
|
164
|
+
headers: dict[str, Any] | None = None,
|
|
165
|
+
display_name: str | None = None,
|
|
166
|
+
make_default: bool = False,
|
|
167
|
+
organization_id: str | None = None,
|
|
168
|
+
) -> Any:
|
|
169
|
+
"""Register an MCP server as a credential."""
|
|
170
|
+
body: dict[str, Any] = {"server_url": server_url, "make_default": make_default}
|
|
171
|
+
if headers is not None:
|
|
172
|
+
body["headers"] = headers
|
|
173
|
+
if display_name is not None:
|
|
174
|
+
body["display_name"] = display_name
|
|
175
|
+
return await self._post("/credentials/mcp-server", json=body, organization_id=organization_id)
|
|
176
|
+
|
|
177
|
+
async def refresh_mcp_discovery(self, credential_id: str, *, organization_id: str | None = None) -> Any:
|
|
178
|
+
"""Refresh the tool discovery for an MCP server credential."""
|
|
179
|
+
return await self._post(
|
|
180
|
+
f"/credentials/{credential_id}/refresh-discovery",
|
|
181
|
+
organization_id=organization_id,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
async def mcp_tools(self, credential_id: str, *, organization_id: str | None = None) -> Any:
|
|
185
|
+
"""Return the list of tools exposed by an MCP server credential."""
|
|
186
|
+
return await self._get(
|
|
187
|
+
f"/credentials/{credential_id}/mcp-tools",
|
|
188
|
+
organization_id=organization_id,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def bulk_modulex_keys_stream(self, *, organization_id: str | None = None) -> EventSourceStream:
|
|
192
|
+
"""Open an SSE stream to receive bulk ModuleX key data."""
|
|
193
|
+
return self._stream_sse(
|
|
194
|
+
"/credentials/bulk-modulex-keys/stream",
|
|
195
|
+
method="POST",
|
|
196
|
+
organization_id=organization_id,
|
|
197
|
+
)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Dashboard resource for the ModuleX Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from modulex._base import _BaseResource
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Dashboard(_BaseResource):
|
|
11
|
+
"""Resource for accessing dashboard logs, analytics, and user management."""
|
|
12
|
+
|
|
13
|
+
async def logs(
|
|
14
|
+
self,
|
|
15
|
+
*,
|
|
16
|
+
limit: int = 50,
|
|
17
|
+
offset: int = 0,
|
|
18
|
+
category: str | None = None,
|
|
19
|
+
operation: str | None = None,
|
|
20
|
+
start_date: str | None = None,
|
|
21
|
+
end_date: str | None = None,
|
|
22
|
+
organization_id: str | None = None,
|
|
23
|
+
) -> Any:
|
|
24
|
+
"""Return activity logs for the organization with optional filters."""
|
|
25
|
+
params: dict[str, Any] = {
|
|
26
|
+
k: v
|
|
27
|
+
for k, v in {
|
|
28
|
+
"limit": limit,
|
|
29
|
+
"offset": offset,
|
|
30
|
+
"category": category,
|
|
31
|
+
"operation": operation,
|
|
32
|
+
"start_date": start_date,
|
|
33
|
+
"end_date": end_date,
|
|
34
|
+
}.items()
|
|
35
|
+
if v is not None
|
|
36
|
+
}
|
|
37
|
+
return await self._get("/dashboard/logs", params=params, organization_id=organization_id)
|
|
38
|
+
|
|
39
|
+
async def analytics_overview(
|
|
40
|
+
self,
|
|
41
|
+
*,
|
|
42
|
+
limit: int = 20,
|
|
43
|
+
offset: int = 0,
|
|
44
|
+
organization_id: str | None = None,
|
|
45
|
+
) -> Any:
|
|
46
|
+
"""Return a high-level analytics overview for the organization."""
|
|
47
|
+
params: dict[str, Any] = {"limit": limit, "offset": offset}
|
|
48
|
+
return await self._get(
|
|
49
|
+
"/dashboard/analytics/overview",
|
|
50
|
+
params=params,
|
|
51
|
+
organization_id=organization_id,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async def analytics_tools(
|
|
55
|
+
self,
|
|
56
|
+
*,
|
|
57
|
+
period: str = "7d",
|
|
58
|
+
limit: int = 20,
|
|
59
|
+
offset: int = 0,
|
|
60
|
+
organization_id: str | None = None,
|
|
61
|
+
) -> Any:
|
|
62
|
+
"""Return tool usage analytics for the organization over a given period."""
|
|
63
|
+
params: dict[str, Any] = {"period": period, "limit": limit, "offset": offset}
|
|
64
|
+
return await self._get(
|
|
65
|
+
"/dashboard/analytics/tools",
|
|
66
|
+
params=params,
|
|
67
|
+
organization_id=organization_id,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
async def analytics_llm_usage(
|
|
71
|
+
self,
|
|
72
|
+
*,
|
|
73
|
+
period: str = "7d",
|
|
74
|
+
limit: int = 20,
|
|
75
|
+
offset: int = 0,
|
|
76
|
+
organization_id: str | None = None,
|
|
77
|
+
) -> Any:
|
|
78
|
+
"""Return LLM token consumption analytics for the organization over a given period."""
|
|
79
|
+
params: dict[str, Any] = {"period": period, "limit": limit, "offset": offset}
|
|
80
|
+
return await self._get(
|
|
81
|
+
"/dashboard/analytics/llm-usage",
|
|
82
|
+
params=params,
|
|
83
|
+
organization_id=organization_id,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
async def users(
|
|
87
|
+
self,
|
|
88
|
+
*,
|
|
89
|
+
search: str | None = None,
|
|
90
|
+
status: str | None = None,
|
|
91
|
+
sort_by: str = "created_at",
|
|
92
|
+
order: str = "desc",
|
|
93
|
+
page: int = 1,
|
|
94
|
+
limit: int = 10,
|
|
95
|
+
organization_id: str | None = None,
|
|
96
|
+
) -> Any:
|
|
97
|
+
"""Return paginated users for the organization with optional search and sort."""
|
|
98
|
+
params: dict[str, Any] = {
|
|
99
|
+
k: v
|
|
100
|
+
for k, v in {
|
|
101
|
+
"search": search,
|
|
102
|
+
"status": status,
|
|
103
|
+
"sort_by": sort_by,
|
|
104
|
+
"order": order,
|
|
105
|
+
"page": page,
|
|
106
|
+
"limit": limit,
|
|
107
|
+
}.items()
|
|
108
|
+
if v is not None
|
|
109
|
+
}
|
|
110
|
+
return await self._get("/dashboard/users", params=params, organization_id=organization_id)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Deployments resource for the ModuleX Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from modulex._base import _BaseResource
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Deployments(_BaseResource):
|
|
11
|
+
"""Resource for managing workflow deployments."""
|
|
12
|
+
|
|
13
|
+
async def create(
|
|
14
|
+
self,
|
|
15
|
+
workflow_id: str,
|
|
16
|
+
*,
|
|
17
|
+
deployment_note: str | None = None,
|
|
18
|
+
schema_image_url: str | None = None,
|
|
19
|
+
organization_id: str | None = None,
|
|
20
|
+
) -> Any:
|
|
21
|
+
"""Deploy a workflow and create a new deployment record."""
|
|
22
|
+
body: dict[str, Any] = {}
|
|
23
|
+
if deployment_note is not None:
|
|
24
|
+
body["deployment_note"] = deployment_note
|
|
25
|
+
if schema_image_url is not None:
|
|
26
|
+
body["schema_image_url"] = schema_image_url
|
|
27
|
+
return await self._post(
|
|
28
|
+
f"/workflows/{workflow_id}/deploy",
|
|
29
|
+
json=body or None,
|
|
30
|
+
organization_id=organization_id,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
async def list(
|
|
34
|
+
self,
|
|
35
|
+
workflow_id: str,
|
|
36
|
+
*,
|
|
37
|
+
limit: int = 20,
|
|
38
|
+
offset: int = 0,
|
|
39
|
+
organization_id: str | None = None,
|
|
40
|
+
) -> Any:
|
|
41
|
+
"""Return a paginated list of deployments for a workflow."""
|
|
42
|
+
return await self._get(
|
|
43
|
+
f"/workflows/{workflow_id}/deployments",
|
|
44
|
+
params={"limit": limit, "offset": offset},
|
|
45
|
+
organization_id=organization_id,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
async def get(
|
|
49
|
+
self,
|
|
50
|
+
workflow_id: str,
|
|
51
|
+
deployment_id: str,
|
|
52
|
+
*,
|
|
53
|
+
organization_id: str | None = None,
|
|
54
|
+
) -> Any:
|
|
55
|
+
"""Return a single deployment by workflow ID and deployment ID."""
|
|
56
|
+
return await self._get(
|
|
57
|
+
f"/workflows/{workflow_id}/deployments/{deployment_id}",
|
|
58
|
+
organization_id=organization_id,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
async def activate(
|
|
62
|
+
self,
|
|
63
|
+
workflow_id: str,
|
|
64
|
+
deployment_id: str,
|
|
65
|
+
*,
|
|
66
|
+
organization_id: str | None = None,
|
|
67
|
+
) -> Any:
|
|
68
|
+
"""Activate a specific deployment, making it the live version."""
|
|
69
|
+
return await self._put(
|
|
70
|
+
f"/workflows/{workflow_id}/deployments/{deployment_id}/activate",
|
|
71
|
+
organization_id=organization_id,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
async def deactivate(self, workflow_id: str, *, organization_id: str | None = None) -> Any:
|
|
75
|
+
"""Deactivate the currently live deployment for a workflow."""
|
|
76
|
+
return await self._delete(
|
|
77
|
+
f"/workflows/{workflow_id}/deployments/live",
|
|
78
|
+
organization_id=organization_id,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
async def delete(
|
|
82
|
+
self,
|
|
83
|
+
workflow_id: str,
|
|
84
|
+
deployment_id: str,
|
|
85
|
+
*,
|
|
86
|
+
organization_id: str | None = None,
|
|
87
|
+
) -> Any:
|
|
88
|
+
"""Permanently delete a deployment by workflow ID and deployment ID."""
|
|
89
|
+
return await self._delete(
|
|
90
|
+
f"/workflows/{workflow_id}/deployments/{deployment_id}",
|
|
91
|
+
organization_id=organization_id,
|
|
92
|
+
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Executions resource for the ModuleX Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from modulex._base import _BaseResource
|
|
8
|
+
from modulex._streaming import EventSourceStream
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Executions(_BaseResource):
|
|
12
|
+
"""Resource for running and managing workflow executions."""
|
|
13
|
+
|
|
14
|
+
async def run(
|
|
15
|
+
self,
|
|
16
|
+
*,
|
|
17
|
+
workflow_id: str | None = None,
|
|
18
|
+
workflow: dict[str, Any] | None = None,
|
|
19
|
+
llm: dict[str, Any] | None = None,
|
|
20
|
+
system_workflow: str | None = None,
|
|
21
|
+
input: dict[str, Any] | None = None,
|
|
22
|
+
config: dict[str, Any] | None = None,
|
|
23
|
+
stream: bool = True,
|
|
24
|
+
ephemeral: bool = False,
|
|
25
|
+
is_private: bool = False,
|
|
26
|
+
knowledge_config: dict[str, Any] | None = None,
|
|
27
|
+
organization_id: str | None = None,
|
|
28
|
+
) -> Any:
|
|
29
|
+
"""Trigger a workflow execution and return the run result or stream handle."""
|
|
30
|
+
body: dict[str, Any] = {
|
|
31
|
+
"stream": stream,
|
|
32
|
+
"ephemeral": ephemeral,
|
|
33
|
+
"is_private": is_private,
|
|
34
|
+
}
|
|
35
|
+
if workflow_id is not None:
|
|
36
|
+
body["workflow_id"] = workflow_id
|
|
37
|
+
if workflow is not None:
|
|
38
|
+
body["workflow"] = workflow
|
|
39
|
+
if llm is not None:
|
|
40
|
+
body["llm"] = llm
|
|
41
|
+
if system_workflow is not None:
|
|
42
|
+
body["system_workflow"] = system_workflow
|
|
43
|
+
if input is not None:
|
|
44
|
+
body["input"] = input
|
|
45
|
+
if config is not None:
|
|
46
|
+
body["config"] = config
|
|
47
|
+
if knowledge_config is not None:
|
|
48
|
+
body["knowledge_config"] = knowledge_config
|
|
49
|
+
return await self._post("/workflows/run", json=body, organization_id=organization_id)
|
|
50
|
+
|
|
51
|
+
async def get_state(self, thread_id: str, *, organization_id: str | None = None) -> Any:
|
|
52
|
+
"""Return the current state of a workflow thread."""
|
|
53
|
+
return await self._get(f"/workflows/state/{thread_id}", organization_id=organization_id)
|
|
54
|
+
|
|
55
|
+
async def resume(
|
|
56
|
+
self,
|
|
57
|
+
thread_id: str,
|
|
58
|
+
run_id: str,
|
|
59
|
+
resume_value: Any,
|
|
60
|
+
*,
|
|
61
|
+
workflow_id: str | None = None,
|
|
62
|
+
workflow: dict[str, Any] | None = None,
|
|
63
|
+
stream: bool = True,
|
|
64
|
+
organization_id: str | None = None,
|
|
65
|
+
) -> Any:
|
|
66
|
+
"""Resume a paused workflow thread with the provided resume value."""
|
|
67
|
+
body: dict[str, Any] = {
|
|
68
|
+
"run_id": run_id,
|
|
69
|
+
"resume_value": resume_value,
|
|
70
|
+
"stream": stream,
|
|
71
|
+
}
|
|
72
|
+
if workflow_id is not None:
|
|
73
|
+
body["workflow_id"] = workflow_id
|
|
74
|
+
if workflow is not None:
|
|
75
|
+
body["workflow"] = workflow
|
|
76
|
+
return await self._post(f"/workflows/resume/{thread_id}", json=body, organization_id=organization_id)
|
|
77
|
+
|
|
78
|
+
async def cancel(
|
|
79
|
+
self,
|
|
80
|
+
run_id: str,
|
|
81
|
+
*,
|
|
82
|
+
reason: str | None = None,
|
|
83
|
+
organization_id: str | None = None,
|
|
84
|
+
) -> Any:
|
|
85
|
+
"""Cancel an in-progress workflow run by its run ID."""
|
|
86
|
+
body: dict[str, Any] = {}
|
|
87
|
+
if reason is not None:
|
|
88
|
+
body["reason"] = reason
|
|
89
|
+
return await self._post(
|
|
90
|
+
f"/workflows/cancel/{run_id}",
|
|
91
|
+
json=body or None,
|
|
92
|
+
organization_id=organization_id,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def listen(self, run_id: str, *, organization_id: str | None = None) -> EventSourceStream:
|
|
96
|
+
"""Open an SSE stream to receive live events for a workflow run."""
|
|
97
|
+
return self._stream_sse(f"/workflows/listen/{run_id}", organization_id=organization_id)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Integrations resource for the ModuleX Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from modulex._base import _BaseResource
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Integrations(_BaseResource):
|
|
11
|
+
"""Resource for browsing and inspecting available integrations."""
|
|
12
|
+
|
|
13
|
+
async def browse(
|
|
14
|
+
self,
|
|
15
|
+
*,
|
|
16
|
+
category: str | None = None,
|
|
17
|
+
type: str | None = None,
|
|
18
|
+
auth_type: str | None = None,
|
|
19
|
+
search: str | None = None,
|
|
20
|
+
include_details: bool = True,
|
|
21
|
+
paginate: bool = True,
|
|
22
|
+
page: int = 1,
|
|
23
|
+
page_size: int = 50,
|
|
24
|
+
organization_id: str | None = None,
|
|
25
|
+
) -> Any:
|
|
26
|
+
"""Browse all available integrations with optional filters and pagination."""
|
|
27
|
+
params: dict[str, Any] = {
|
|
28
|
+
k: v
|
|
29
|
+
for k, v in {
|
|
30
|
+
"category": category,
|
|
31
|
+
"type": type,
|
|
32
|
+
"auth_type": auth_type,
|
|
33
|
+
"search": search,
|
|
34
|
+
"include_details": include_details,
|
|
35
|
+
"paginate": paginate,
|
|
36
|
+
"page": page,
|
|
37
|
+
"page_size": page_size,
|
|
38
|
+
}.items()
|
|
39
|
+
if v is not None
|
|
40
|
+
}
|
|
41
|
+
return await self._get("/integrations/browse", params=params, organization_id=organization_id)
|
|
42
|
+
|
|
43
|
+
async def tools(
|
|
44
|
+
self,
|
|
45
|
+
*,
|
|
46
|
+
category: str | None = None,
|
|
47
|
+
organization_id: str | None = None,
|
|
48
|
+
) -> Any:
|
|
49
|
+
"""Return available tool integrations, optionally filtered by category."""
|
|
50
|
+
params: dict[str, Any] = {k: v for k, v in {"category": category}.items() if v is not None}
|
|
51
|
+
return await self._get("/integrations/tools", params=params, organization_id=organization_id)
|
|
52
|
+
|
|
53
|
+
async def tool_detail(
|
|
54
|
+
self,
|
|
55
|
+
integration_name: str,
|
|
56
|
+
*,
|
|
57
|
+
organization_id: str | None = None,
|
|
58
|
+
) -> Any:
|
|
59
|
+
"""Return detailed information for a single tool integration by name."""
|
|
60
|
+
return await self._get(f"/integrations/tools/{integration_name}", organization_id=organization_id)
|
|
61
|
+
|
|
62
|
+
async def llm_providers(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
category: str | None = None,
|
|
66
|
+
organization_id: str | None = None,
|
|
67
|
+
) -> Any:
|
|
68
|
+
"""Return available LLM provider integrations, optionally filtered by category."""
|
|
69
|
+
params: dict[str, Any] = {k: v for k, v in {"category": category}.items() if v is not None}
|
|
70
|
+
return await self._get("/integrations/llm-providers", params=params, organization_id=organization_id)
|
|
71
|
+
|
|
72
|
+
async def llm_provider_detail(
|
|
73
|
+
self,
|
|
74
|
+
provider_name: str,
|
|
75
|
+
*,
|
|
76
|
+
organization_id: str | None = None,
|
|
77
|
+
) -> Any:
|
|
78
|
+
"""Return detailed information for a single LLM provider by name."""
|
|
79
|
+
return await self._get(f"/integrations/llm-providers/{provider_name}", organization_id=organization_id)
|
|
80
|
+
|
|
81
|
+
async def knowledge_providers(
|
|
82
|
+
self,
|
|
83
|
+
*,
|
|
84
|
+
category: str | None = None,
|
|
85
|
+
organization_id: str | None = None,
|
|
86
|
+
) -> Any:
|
|
87
|
+
"""Return available knowledge provider integrations, optionally filtered by category."""
|
|
88
|
+
params: dict[str, Any] = {k: v for k, v in {"category": category}.items() if v is not None}
|
|
89
|
+
return await self._get("/integrations/knowledge-providers", params=params, organization_id=organization_id)
|
|
90
|
+
|
|
91
|
+
async def knowledge_provider_detail(
|
|
92
|
+
self,
|
|
93
|
+
provider_name: str,
|
|
94
|
+
*,
|
|
95
|
+
organization_id: str | None = None,
|
|
96
|
+
) -> Any:
|
|
97
|
+
"""Return detailed information for a single knowledge provider by name."""
|
|
98
|
+
return await self._get(
|
|
99
|
+
f"/integrations/knowledge-providers/{provider_name}",
|
|
100
|
+
organization_id=organization_id,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def get(
|
|
104
|
+
self,
|
|
105
|
+
integration_name: str,
|
|
106
|
+
*,
|
|
107
|
+
organization_id: str | None = None,
|
|
108
|
+
) -> Any:
|
|
109
|
+
"""Return the integration record for a given integration name."""
|
|
110
|
+
return await self._get(f"/integrations/{integration_name}", organization_id=organization_id)
|