stacklink-sdk 0.2.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.
- stacklink/__init__.py +42 -0
- stacklink/api_keys.py +18 -0
- stacklink/artifacts.py +9 -0
- stacklink/auth_configs.py +29 -0
- stacklink/billing.py +43 -0
- stacklink/claude_agent.py +29 -0
- stacklink/client.py +292 -0
- stacklink/connected_accounts.py +95 -0
- stacklink/errors.py +15 -0
- stacklink/executions.py +45 -0
- stacklink/knowledge.py +24 -0
- stacklink/logs.py +29 -0
- stacklink/mcp.py +76 -0
- stacklink/memory.py +235 -0
- stacklink/openai_agents.py +40 -0
- stacklink/openai_memory.py +432 -0
- stacklink/projects.py +20 -0
- stacklink/sessions.py +223 -0
- stacklink/tools.py +144 -0
- stacklink/triggers.py +27 -0
- stacklink/types.py +290 -0
- stacklink/webhooks.py +29 -0
- stacklink/workbench.py +1090 -0
- stacklink_sdk-0.2.0.dist-info/METADATA +71 -0
- stacklink_sdk-0.2.0.dist-info/RECORD +28 -0
- stacklink_sdk-0.2.0.dist-info/WHEEL +5 -0
- stacklink_sdk-0.2.0.dist-info/licenses/LICENSE +9 -0
- stacklink_sdk-0.2.0.dist-info/top_level.txt +1 -0
stacklink/tools.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .types import Json, ToolSchemasResponse, ToolSearchResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ToolsResource:
|
|
10
|
+
def __init__(self, client):
|
|
11
|
+
self.client = client
|
|
12
|
+
|
|
13
|
+
def search(self, body: dict[str, Any]) -> ToolSearchResponse:
|
|
14
|
+
return self.client.request("POST", "/v1/tools/search", json_body=body)
|
|
15
|
+
|
|
16
|
+
def search_for_session(self, session_id: str, body: dict[str, Any], *, cache: str = "default") -> ToolSearchResponse:
|
|
17
|
+
search_body = {
|
|
18
|
+
"responseMode": "compact",
|
|
19
|
+
"includeSchemas": False,
|
|
20
|
+
"includeRelatedTools": False,
|
|
21
|
+
"includeExecutionPlan": False,
|
|
22
|
+
**body,
|
|
23
|
+
}
|
|
24
|
+
payload = _server_cache_body(search_body, cache)
|
|
25
|
+
return self.client.cached_request(
|
|
26
|
+
f"session:{session_id}:search:{_stable_json(_without_cache_control(search_body))}",
|
|
27
|
+
"POST",
|
|
28
|
+
f"/v1/sessions/{session_id}/tools/search",
|
|
29
|
+
json_body=payload,
|
|
30
|
+
bypass_cache=cache == "bypass",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def schemas(self, body: dict[str, Any]) -> ToolSchemasResponse:
|
|
34
|
+
return self.client.request("POST", "/v1/tools/schemas", json_body=body)
|
|
35
|
+
|
|
36
|
+
def schemas_for_session(self, session_id: str, body: dict[str, Any], *, cache: str = "default") -> ToolSchemasResponse:
|
|
37
|
+
payload = _server_cache_body(body, cache)
|
|
38
|
+
return self.client.cached_request(
|
|
39
|
+
f"session:{session_id}:schemas:{_stable_json(_without_cache_control(body))}",
|
|
40
|
+
"POST",
|
|
41
|
+
f"/v1/sessions/{session_id}/tools/schemas",
|
|
42
|
+
json_body=payload,
|
|
43
|
+
bypass_cache=cache == "bypass",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def runtime_contracts(self, body: dict[str, Any]) -> dict[str, Any]:
|
|
47
|
+
return self.client.request("POST", "/v1/tools/runtime-contracts", json_body=body)
|
|
48
|
+
|
|
49
|
+
def runtime_contracts_for_session(self, session_id: str, body: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
50
|
+
return self.client.request(
|
|
51
|
+
"POST",
|
|
52
|
+
f"/v1/sessions/{session_id}/tools/runtime-contracts",
|
|
53
|
+
json_body=body or {},
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def prepare_runtime_for_session(
|
|
57
|
+
self,
|
|
58
|
+
session_id: str,
|
|
59
|
+
*,
|
|
60
|
+
toolkit_keys: list[str] | None = None,
|
|
61
|
+
tool_keys: list[str] | None = None,
|
|
62
|
+
include_planned: bool = False,
|
|
63
|
+
) -> dict[str, Any]:
|
|
64
|
+
return self.runtime_contracts_for_session(session_id, {
|
|
65
|
+
**({"toolkitKeys": toolkit_keys} if toolkit_keys else {}),
|
|
66
|
+
**({"toolKeys": tool_keys} if tool_keys else {}),
|
|
67
|
+
"includePlanned": include_planned,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
def prepare_for_session(
|
|
71
|
+
self,
|
|
72
|
+
session_id: str,
|
|
73
|
+
*,
|
|
74
|
+
intents: list[str],
|
|
75
|
+
include_schemas: bool = True,
|
|
76
|
+
limit_per_intent: int = 5,
|
|
77
|
+
include_planned: bool = False,
|
|
78
|
+
toolkit_key: str | None = None,
|
|
79
|
+
capability: str | None = None,
|
|
80
|
+
model: str | None = None,
|
|
81
|
+
cache: str = "default",
|
|
82
|
+
) -> dict[str, Any]:
|
|
83
|
+
search = self.search_for_session(session_id, {
|
|
84
|
+
"responseMode": "compact",
|
|
85
|
+
"includeSchemas": False,
|
|
86
|
+
"includeRelatedTools": False,
|
|
87
|
+
"includeExecutionPlan": False,
|
|
88
|
+
"queries": [
|
|
89
|
+
{
|
|
90
|
+
"query": intent,
|
|
91
|
+
"limit": limit_per_intent,
|
|
92
|
+
**({"toolkitKey": toolkit_key} if toolkit_key else {}),
|
|
93
|
+
**({"capability": capability} if capability else {}),
|
|
94
|
+
}
|
|
95
|
+
for intent in intents
|
|
96
|
+
],
|
|
97
|
+
"includePlanned": include_planned,
|
|
98
|
+
"limit": max(limit_per_intent, len(intents) * limit_per_intent),
|
|
99
|
+
**({"model": model} if model else {}),
|
|
100
|
+
}, cache=cache)
|
|
101
|
+
tools = search.get("tools", []) if isinstance(search, dict) else []
|
|
102
|
+
tool_keys = []
|
|
103
|
+
for tool in tools:
|
|
104
|
+
key = tool.get("key") if isinstance(tool, dict) else None
|
|
105
|
+
if isinstance(key, str) and key not in tool_keys:
|
|
106
|
+
tool_keys.append(key)
|
|
107
|
+
schemas = self.schemas_for_session(
|
|
108
|
+
session_id,
|
|
109
|
+
{"toolKeys": tool_keys, "includePlanned": include_planned},
|
|
110
|
+
cache=cache,
|
|
111
|
+
) if include_schemas and tool_keys else {"tools": []}
|
|
112
|
+
return {
|
|
113
|
+
"tools": tools,
|
|
114
|
+
"schemas": schemas.get("tools", []) if isinstance(schemas, dict) else [],
|
|
115
|
+
"toolKeys": tool_keys,
|
|
116
|
+
"search": search,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
def execute(self, body: dict[str, Any]) -> Json:
|
|
120
|
+
return self.client.request("POST", "/v1/tools/execute", json_body=body)
|
|
121
|
+
|
|
122
|
+
def execute_for_session(self, session_id: str, body: dict[str, Any]) -> Json:
|
|
123
|
+
return self.client.request("POST", f"/v1/sessions/{session_id}/tools/execute", json_body=body)
|
|
124
|
+
|
|
125
|
+
def execute_batch(self, body: dict[str, Any]) -> Json:
|
|
126
|
+
return self.client.request("POST", "/v1/tools/execute-batch", json_body=body)
|
|
127
|
+
|
|
128
|
+
def execute_batch_for_session(self, session_id: str, body: dict[str, Any]) -> Json:
|
|
129
|
+
return self.client.request("POST", f"/v1/sessions/{session_id}/tools/execute-batch", json_body=body)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _without_cache_control(body: dict[str, Any]) -> dict[str, Any]:
|
|
133
|
+
return {key: value for key, value in body.items() if key != "cache"}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _server_cache_body(body: dict[str, Any], cache: str) -> dict[str, Any]:
|
|
137
|
+
payload = _without_cache_control(body)
|
|
138
|
+
if cache == "bypass":
|
|
139
|
+
payload["cache"] = "bypass"
|
|
140
|
+
return payload
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _stable_json(value: Any) -> str:
|
|
144
|
+
return json.dumps(value, sort_keys=True, separators=(",", ":"), default=str)
|
stacklink/triggers.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TriggersResource:
|
|
7
|
+
def __init__(self, client):
|
|
8
|
+
self.client = client
|
|
9
|
+
|
|
10
|
+
def types(self, **query):
|
|
11
|
+
return self.client.request("GET", "/v1/triggers/types", query=query)
|
|
12
|
+
|
|
13
|
+
def list(self, **query):
|
|
14
|
+
return self.client.request("GET", "/v1/triggers/subscriptions", query=query)
|
|
15
|
+
|
|
16
|
+
def create(self, body: dict[str, Any]):
|
|
17
|
+
return self.client.request("POST", "/v1/triggers/subscriptions", json_body=body)
|
|
18
|
+
|
|
19
|
+
def get(self, subscription_id: str):
|
|
20
|
+
return self.client.request("GET", f"/v1/triggers/subscriptions/{subscription_id}")
|
|
21
|
+
|
|
22
|
+
def update(self, subscription_id: str, body: dict[str, Any]):
|
|
23
|
+
return self.client.request("PATCH", f"/v1/triggers/subscriptions/{subscription_id}", json_body=body)
|
|
24
|
+
|
|
25
|
+
def delete(self, subscription_id: str):
|
|
26
|
+
return self.client.request("DELETE", f"/v1/triggers/subscriptions/{subscription_id}")
|
|
27
|
+
|
stacklink/types.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, Literal, Mapping, MutableMapping, Optional, Tuple, TypedDict
|
|
4
|
+
|
|
5
|
+
Json = Any
|
|
6
|
+
JsonObject = dict[str, Any]
|
|
7
|
+
Headers = Mapping[str, str]
|
|
8
|
+
Transport = Callable[[str, str, Headers, Optional[Json], Mapping[str, Any], float], Tuple[int, MutableMapping[str, str], Json]]
|
|
9
|
+
|
|
10
|
+
BillingClass = Literal["standard", "premium", "free"]
|
|
11
|
+
BillingUnit = Literal["call", "runtime_10s", "token_block", "byte_block"]
|
|
12
|
+
BillingQuantitySource = Literal["fixed", "duration_ms", "tokens", "bytes"]
|
|
13
|
+
BillingVersion = Literal["stacklink-billing-v1"]
|
|
14
|
+
PricingProductArea = Literal["provider", "knowledge", "model", "workbench", "platform"]
|
|
15
|
+
PricingUnit = Literal[
|
|
16
|
+
"operation",
|
|
17
|
+
"call",
|
|
18
|
+
"1000_calls",
|
|
19
|
+
"1m_input_tokens",
|
|
20
|
+
"1m_output_tokens",
|
|
21
|
+
"1m_reasoning_tokens",
|
|
22
|
+
"runtime_10s",
|
|
23
|
+
"byte_block",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
StacklinkBillingDescriptor = TypedDict(
|
|
27
|
+
"StacklinkBillingDescriptor",
|
|
28
|
+
{
|
|
29
|
+
"class": BillingClass,
|
|
30
|
+
"unit": BillingUnit,
|
|
31
|
+
"multiplier": Literal[1, 2, 3],
|
|
32
|
+
"quantitySource": BillingQuantitySource,
|
|
33
|
+
"version": BillingVersion,
|
|
34
|
+
},
|
|
35
|
+
total=False,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class StacklinkExecutionCapability(TypedDict, total=False):
|
|
40
|
+
cancellable: Literal["hard", "cooperative", "request_only", "none"]
|
|
41
|
+
streamingSupport: Literal["none", "progress", "output_delta", "both"]
|
|
42
|
+
backgroundSupport: Literal["none", "optional", "required"]
|
|
43
|
+
defaultTimeoutMs: int
|
|
44
|
+
maxTimeoutMs: int
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
ProviderConnectorType = Literal["app", "platform", "sandbox", "api"]
|
|
48
|
+
ProviderRuntimeKind = Literal["native_api", "native_sdk", "remote_mcp", "managed_mcp_gateway"]
|
|
49
|
+
ProviderRuntimeOwner = Literal["stacklink", "provider", "third_party"]
|
|
50
|
+
ProviderMcpTransport = Literal["streamable_http"]
|
|
51
|
+
ProviderMcpAuthType = Literal["oauth_dcr", "oauth_static_client", "bearer", "none"]
|
|
52
|
+
ProviderMcpImportPolicy = Literal["certified_allowlist", "discover_then_review"]
|
|
53
|
+
ProviderMcpIdentityKind = Literal["user", "workspace", "organization", "project"]
|
|
54
|
+
ProviderMcpResourceKind = Literal[
|
|
55
|
+
"user",
|
|
56
|
+
"workspace",
|
|
57
|
+
"organization",
|
|
58
|
+
"project",
|
|
59
|
+
"site",
|
|
60
|
+
"repository",
|
|
61
|
+
"channel",
|
|
62
|
+
"folder",
|
|
63
|
+
"database",
|
|
64
|
+
]
|
|
65
|
+
ConnectionRequestPhase = Literal[
|
|
66
|
+
"request_created",
|
|
67
|
+
"connect_page_opened",
|
|
68
|
+
"oauth_started",
|
|
69
|
+
"provider_authorizing",
|
|
70
|
+
"oauth_callback_received",
|
|
71
|
+
"token_exchange_started",
|
|
72
|
+
"account_storing",
|
|
73
|
+
"remote_mcp_tools_importing",
|
|
74
|
+
"remote_mcp_tools_imported",
|
|
75
|
+
"completed",
|
|
76
|
+
"failed",
|
|
77
|
+
"expired",
|
|
78
|
+
]
|
|
79
|
+
ConnectionRequestNextAction = Literal[
|
|
80
|
+
"open_connect_url",
|
|
81
|
+
"continue_to_provider",
|
|
82
|
+
"wait_for_user",
|
|
83
|
+
"wait_for_provider",
|
|
84
|
+
"wait_for_stacklink",
|
|
85
|
+
"refresh_toolkits",
|
|
86
|
+
"retry",
|
|
87
|
+
"none",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ProviderProfileCapabilityItem(TypedDict):
|
|
92
|
+
key: str
|
|
93
|
+
label: str
|
|
94
|
+
description: str
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ProviderProfileCapabilityGroup(TypedDict):
|
|
98
|
+
key: str
|
|
99
|
+
title: str
|
|
100
|
+
items: list[ProviderProfileCapabilityItem]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ProviderProfileDetails(TypedDict, total=False):
|
|
104
|
+
connectorType: ProviderConnectorType
|
|
105
|
+
author: Literal["Stacklink"]
|
|
106
|
+
providerKey: str
|
|
107
|
+
websiteUrl: str
|
|
108
|
+
docsUrl: str
|
|
109
|
+
privacyPolicyUrl: str
|
|
110
|
+
termsUrl: str
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ProviderMarketplaceMetadata(TypedDict):
|
|
114
|
+
visible: bool
|
|
115
|
+
connectable: bool
|
|
116
|
+
recommended: bool
|
|
117
|
+
internal: bool
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class ProviderProfile(TypedDict):
|
|
121
|
+
headline: str
|
|
122
|
+
summary: str
|
|
123
|
+
examplePrompts: list[str]
|
|
124
|
+
capabilityGroups: list[ProviderProfileCapabilityGroup]
|
|
125
|
+
accessText: str
|
|
126
|
+
authText: str
|
|
127
|
+
safetyText: str
|
|
128
|
+
details: ProviderProfileDetails
|
|
129
|
+
marketplace: ProviderMarketplaceMetadata
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class ProviderMcpAuth(TypedDict):
|
|
133
|
+
type: ProviderMcpAuthType
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class ProviderMcpIdentity(TypedDict, total=False):
|
|
137
|
+
strategy: Literal["tool_call"]
|
|
138
|
+
identityKind: ProviderMcpIdentityKind
|
|
139
|
+
toolName: str
|
|
140
|
+
arguments: JsonObject
|
|
141
|
+
payloadRoot: JsonObject
|
|
142
|
+
externalAccountIdPath: list[str]
|
|
143
|
+
displayNamePath: list[str]
|
|
144
|
+
displayNameTemplate: str
|
|
145
|
+
metadataPaths: dict[str, list[str]]
|
|
146
|
+
fallbackDisplayName: str
|
|
147
|
+
timeoutMs: int
|
|
148
|
+
contractVersion: int
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class ProviderMcpResourceParent(TypedDict, total=False):
|
|
152
|
+
kind: ProviderMcpResourceKind
|
|
153
|
+
externalResourceIdPath: list[str]
|
|
154
|
+
labelPath: list[str]
|
|
155
|
+
labelTemplate: str
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class ProviderMcpResourceEnrichment(TypedDict, total=False):
|
|
159
|
+
toolName: str
|
|
160
|
+
argumentsTemplate: JsonObject
|
|
161
|
+
payloadRoot: JsonObject
|
|
162
|
+
metadataPaths: dict[str, list[str]]
|
|
163
|
+
urlPath: list[str]
|
|
164
|
+
timeoutMs: int
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class ProviderMcpResource(TypedDict, total=False):
|
|
168
|
+
key: str
|
|
169
|
+
strategy: Literal["tool_call"]
|
|
170
|
+
resourceKind: ProviderMcpResourceKind
|
|
171
|
+
toolName: str
|
|
172
|
+
arguments: JsonObject
|
|
173
|
+
payloadRoot: JsonObject
|
|
174
|
+
externalResourceIdPath: list[str]
|
|
175
|
+
labelPath: list[str]
|
|
176
|
+
labelTemplate: str
|
|
177
|
+
parent: ProviderMcpResourceParent
|
|
178
|
+
metadataPaths: dict[str, list[str]]
|
|
179
|
+
enrichments: list[ProviderMcpResourceEnrichment]
|
|
180
|
+
timeoutMs: int
|
|
181
|
+
maxItems: int
|
|
182
|
+
contractVersion: int
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class ProviderMcpRuntime(TypedDict, total=False):
|
|
186
|
+
endpointUrl: str
|
|
187
|
+
transport: ProviderMcpTransport
|
|
188
|
+
auth: ProviderMcpAuth
|
|
189
|
+
sourceUrl: str
|
|
190
|
+
importPolicy: ProviderMcpImportPolicy
|
|
191
|
+
allowlisted: bool
|
|
192
|
+
identity: ProviderMcpIdentity
|
|
193
|
+
resources: list[ProviderMcpResource]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class ProviderRuntime(TypedDict, total=False):
|
|
197
|
+
kind: ProviderRuntimeKind
|
|
198
|
+
owner: ProviderRuntimeOwner
|
|
199
|
+
label: str
|
|
200
|
+
mcp: ProviderMcpRuntime
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class ConnectionRequest(TypedDict, total=False):
|
|
204
|
+
id: str
|
|
205
|
+
providerKey: str
|
|
206
|
+
providerName: str
|
|
207
|
+
authConfigId: str | None
|
|
208
|
+
authMode: str | None
|
|
209
|
+
status: str
|
|
210
|
+
phase: ConnectionRequestPhase
|
|
211
|
+
nextAction: ConnectionRequestNextAction
|
|
212
|
+
redirectUrl: str
|
|
213
|
+
callbackUrl: str | None
|
|
214
|
+
failureReason: str | None
|
|
215
|
+
failureCode: str | None
|
|
216
|
+
expiresAt: str
|
|
217
|
+
authModes: list[str]
|
|
218
|
+
authRequirements: list[JsonObject]
|
|
219
|
+
connectedAccount: JsonObject | None
|
|
220
|
+
metadata: Json
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class PublicPricingSummary(TypedDict, total=False):
|
|
224
|
+
billingModel: Literal["included", "free", "metered", "token_metered", "custom"]
|
|
225
|
+
productArea: PricingProductArea
|
|
226
|
+
unit: PricingUnit
|
|
227
|
+
unitLabel: str
|
|
228
|
+
priceMicros: str
|
|
229
|
+
priceText: str
|
|
230
|
+
currency: str
|
|
231
|
+
effectiveFrom: str
|
|
232
|
+
notes: list[str]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class ProviderToolkit(TypedDict, total=False):
|
|
236
|
+
id: str
|
|
237
|
+
key: str
|
|
238
|
+
displayName: str
|
|
239
|
+
category: str
|
|
240
|
+
status: str
|
|
241
|
+
authModes: list[str]
|
|
242
|
+
capabilities: list[str]
|
|
243
|
+
metadata: Json
|
|
244
|
+
brand: Json
|
|
245
|
+
profile: ProviderProfile
|
|
246
|
+
runtime: ProviderRuntime
|
|
247
|
+
pricingSummary: PublicPricingSummary
|
|
248
|
+
createdAt: str
|
|
249
|
+
updatedAt: str
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class ProjectProvider(ProviderToolkit, total=False):
|
|
253
|
+
providerKey: str
|
|
254
|
+
name: str
|
|
255
|
+
projectStatus: str
|
|
256
|
+
toolCount: int
|
|
257
|
+
triggerCount: int
|
|
258
|
+
enabledAt: str | None
|
|
259
|
+
disabledAt: str | None
|
|
260
|
+
connection: Json
|
|
261
|
+
toolkit: ProviderToolkit
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ProviderTool(TypedDict, total=False):
|
|
265
|
+
id: str
|
|
266
|
+
key: str
|
|
267
|
+
toolkitKey: str
|
|
268
|
+
displayName: str
|
|
269
|
+
description: str
|
|
270
|
+
capability: str
|
|
271
|
+
mutationLevel: str
|
|
272
|
+
status: str
|
|
273
|
+
inputSchema: Json
|
|
274
|
+
outputSchema: Json
|
|
275
|
+
searchDescriptor: Json
|
|
276
|
+
metadata: Json
|
|
277
|
+
aliases: list[Json]
|
|
278
|
+
providerProfile: ProviderProfile
|
|
279
|
+
execution: StacklinkExecutionCapability
|
|
280
|
+
billing: StacklinkBillingDescriptor
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class ToolSearchResponse(TypedDict, total=False):
|
|
284
|
+
tools: list[ProviderTool]
|
|
285
|
+
queries: list[Json]
|
|
286
|
+
meta: Json
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class ToolSchemasResponse(TypedDict):
|
|
290
|
+
tools: list[ProviderTool]
|
stacklink/webhooks.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WebhooksResource:
|
|
7
|
+
def __init__(self, client):
|
|
8
|
+
self.client = client
|
|
9
|
+
|
|
10
|
+
def get(self):
|
|
11
|
+
return self.client.request("GET", "/v1/webhook")
|
|
12
|
+
|
|
13
|
+
def update(self, body: dict[str, Any]):
|
|
14
|
+
return self.client.request("PUT", "/v1/webhook", json_body=body)
|
|
15
|
+
|
|
16
|
+
def rotate_secret(self):
|
|
17
|
+
return self.client.request("POST", "/v1/webhook/rotate-secret")
|
|
18
|
+
|
|
19
|
+
def send_test(self, body: dict[str, Any] | None = None):
|
|
20
|
+
return self.client.request("POST", "/v1/webhook/test", json_body=body or {})
|
|
21
|
+
|
|
22
|
+
def retry_delivery(self, delivery_id: str, body: dict[str, Any] | None = None):
|
|
23
|
+
return self.client.request("POST", f"/v1/webhook-deliveries/{delivery_id}/retry", json_body=body or {})
|
|
24
|
+
|
|
25
|
+
def redrive_dead_letters(self, body: dict[str, Any] | None = None):
|
|
26
|
+
return self.client.request("POST", "/v1/webhook-deliveries/dead-letter/redrive", json_body=body or {})
|
|
27
|
+
|
|
28
|
+
def replay_event(self, event_id: str):
|
|
29
|
+
return self.client.request("POST", f"/v1/events/{event_id}/replay")
|