stacklink-sdk 0.3.10__tar.gz → 0.3.13__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.
Files changed (43) hide show
  1. {stacklink_sdk-0.3.10/stacklink_sdk.egg-info → stacklink_sdk-0.3.13}/PKG-INFO +1 -1
  2. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/pyproject.toml +1 -1
  3. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/__init__.py +2 -1
  4. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/bots.py +59 -2
  5. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/client.py +1 -1
  6. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13/stacklink_sdk.egg-info}/PKG-INFO +1 -1
  7. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_client.py +10 -0
  8. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/LICENSE +0 -0
  9. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/README.md +0 -0
  10. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/setup.cfg +0 -0
  11. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/api_keys.py +0 -0
  12. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/approvals.py +0 -0
  13. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/artifacts.py +0 -0
  14. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/auth_configs.py +0 -0
  15. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/billing.py +0 -0
  16. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/claude_agent.py +0 -0
  17. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/connected_accounts.py +0 -0
  18. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/errors.py +0 -0
  19. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/executions.py +0 -0
  20. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/knowledge.py +0 -0
  21. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/logs.py +0 -0
  22. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/mcp.py +0 -0
  23. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/memory.py +0 -0
  24. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/openai_agents.py +0 -0
  25. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/openai_memory.py +0 -0
  26. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/projects.py +0 -0
  27. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/providers.py +0 -0
  28. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/sessions.py +0 -0
  29. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/tools.py +0 -0
  30. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/triggers.py +0 -0
  31. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/types.py +0 -0
  32. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/webhooks.py +0 -0
  33. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/workbench.py +0 -0
  34. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink/x_chat.py +0 -0
  35. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink_sdk.egg-info/SOURCES.txt +0 -0
  36. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink_sdk.egg-info/dependency_links.txt +0 -0
  37. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink_sdk.egg-info/requires.txt +0 -0
  38. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/stacklink_sdk.egg-info/top_level.txt +0 -0
  39. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_google_docs_provider.py +0 -0
  40. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_google_drive_provider.py +0 -0
  41. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_google_sheets_provider.py +0 -0
  42. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_openai_memory.py +0 -0
  43. {stacklink_sdk-0.3.10 → stacklink_sdk-0.3.13}/tests/test_zoho_books_provider.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stacklink-sdk
3
- Version: 0.3.10
3
+ Version: 0.3.13
4
4
  Summary: Python SDK for Stacklink sessions, tools, MCP, auth, workbench, logs, knowledge, and billing.
5
5
  Author: Stacklink
6
6
  License-Expression: LicenseRef-Proprietary
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "stacklink-sdk"
7
- version = "0.3.10"
7
+ version = "0.3.13"
8
8
  description = "Python SDK for Stacklink sessions, tools, MCP, auth, workbench, logs, knowledge, and billing."
9
9
  readme = "README.md"
10
10
  license = "LicenseRef-Proprietary"
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from .bots import verify_bot_api_request, sign_bot_trigger_request
3
+ from .bots import verify_bot_api_request, sign_bot_trigger_request, BotRun, BotConnectionAction, BotExecutionWait, BotCapabilityFact, BotRequirement
4
4
  from .approvals import ApprovalDecision, ApprovalRecord, ApprovalEvent, ApprovalPermissions, CustomerApprovalGrantInput
5
5
  from .webhooks import verify_webhook_signature
6
6
  from .client import AsyncStacklink, STACKLINK_PYTHON_SDK_VERSION, Stacklink
@@ -27,6 +27,7 @@ from .types import (
27
27
  )
28
28
 
29
29
  __all__ = [
30
+ "BotRun", "BotConnectionAction", "BotExecutionWait", "BotCapabilityFact", "BotRequirement",
30
31
  "ApprovalDecision", "ApprovalRecord", "ApprovalEvent", "ApprovalPermissions",
31
32
  "CustomerApprovalGrantInput",
32
33
  "Stacklink",
@@ -1,6 +1,6 @@
1
1
  """Hosted bot management and durable runs for sync and async clients."""
2
2
  from __future__ import annotations
3
- from typing import Any
3
+ from typing import Any, Literal, TypedDict
4
4
  from contextlib import closing, aclosing
5
5
  import asyncio
6
6
  import base64
@@ -15,6 +15,61 @@ from urllib.parse import quote
15
15
  from uuid import uuid4
16
16
 
17
17
 
18
+ class _BotCapabilityAccount(TypedDict, total=False):
19
+ account: Literal["project", "customer"]
20
+
21
+
22
+ class BotCapabilityFact(_BotCapabilityAccount):
23
+ id: str
24
+ status: Literal["enabled", "disabled", "sample"]
25
+ owner: Literal["project_owner", "customer"]
26
+
27
+
28
+ class _BotConnectionDetails(TypedDict, total=False):
29
+ providerName: str
30
+ providerIconUrl: str
31
+ intent: Literal["connect", "reconnect"]
32
+ canResume: bool
33
+
34
+
35
+ class BotConnectionAction(_BotConnectionDetails):
36
+ kind: Literal["connection"]
37
+ id: str
38
+ providerKey: str
39
+ owner: Literal["customer", "project_owner"]
40
+ status: str
41
+ expiresAt: str
42
+ action: dict[str, str] | None
43
+
44
+
45
+ class BotExecutionWait(TypedDict):
46
+ kind: Literal["execution"]
47
+ id: str
48
+
49
+
50
+ class BotRequirement(TypedDict):
51
+ capabilityId: str
52
+ code: str
53
+ owner: Literal["project_owner", "stacklink"]
54
+ nextAction: Literal["configure_bot", "repair_connection", "use_live_data", "contact_administrator", "unavailable"]
55
+
56
+
57
+ class BotRun(TypedDict, total=False):
58
+ id: str
59
+ botId: str
60
+ conversationId: str
61
+ status: str
62
+ finalText: str | None
63
+ output: Any
64
+ error: Any
65
+ waitingOperation: BotConnectionAction | BotExecutionWait | None
66
+ connection: BotConnectionAction | None
67
+ capabilities: list[BotCapabilityFact]
68
+ requirements: list[BotRequirement]
69
+ usage: dict[str, Any]
70
+ display: dict[str, Any]
71
+
72
+
18
73
  def sign_bot_trigger_request(*, trigger_id: str, secret: str, body: str, request_id: str | None = None, now: float | None = None) -> dict[str, str]:
19
74
  """Sign the exact JSON bytes. Reuse request_id when retrying the same event."""
20
75
  timestamp = str(int(time.time() if now is None else now))
@@ -132,10 +187,12 @@ class BotsResource:
132
187
  def publish(self, bot_id: str, revision: int, channels: dict[str, bool]):
133
188
  return self.client.request("POST", self._path(bot_id) + "/publish", json_body={"revision": revision, "channels": channels})
134
189
 
135
- def run(self, bot_id: str, *, session_id: str, message: str, variables: dict[str, Any] | None = None, conversation_id: str | None = None, run_id: str | None = None):
190
+ def run(self, bot_id: str, *, session_id: str, message: str, variables: dict[str, Any] | None = None, conversation_id: str | None = None, run_id: str | None = None, connection_return_url: str | None = None):
136
191
  body: dict[str, Any] = {"sessionId": session_id, "message": message, "variables": variables or {}, "runId": run_id or str(uuid4())}
137
192
  if conversation_id:
138
193
  body["conversationId"] = conversation_id
194
+ if connection_return_url is not None:
195
+ body["connectionReturnUrl"] = connection_return_url
139
196
  return self.client.request("POST", self._path(bot_id) + "/runs", json_body=body)
140
197
 
141
198
  def get_run(self, bot_id: str, run_id: str):
@@ -37,7 +37,7 @@ from .types import Json, Transport
37
37
  from .webhooks import WebhooksResource
38
38
  from .workbench import WorkbenchResource
39
39
 
40
- STACKLINK_PYTHON_SDK_VERSION = "0.3.10"
40
+ STACKLINK_PYTHON_SDK_VERSION = "0.3.13"
41
41
  STACKLINK_PYTHON_USER_AGENT = f"stacklink-python/{STACKLINK_PYTHON_SDK_VERSION}"
42
42
 
43
43
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stacklink-sdk
3
- Version: 0.3.10
3
+ Version: 0.3.13
4
4
  Summary: Python SDK for Stacklink sessions, tools, MCP, auth, workbench, logs, knowledge, and billing.
5
5
  Author: Stacklink
6
6
  License-Expression: LicenseRef-Proprietary
@@ -130,6 +130,16 @@ class StacklinkClientTests(unittest.TestCase):
130
130
  self.assertEqual(headers["stacklink-signature"], hmac.new(b"fixture", signed.encode(), hashlib.sha256).hexdigest())
131
131
  self.assertNotEqual(headers["stacklink-signature"], sign_bot_trigger_request(trigger_id="trigger-one", secret="fixture", body=body + " ", request_id="event-one", now=1000)["stacklink-signature"])
132
132
 
133
+ def test_bot_connection_return_url_uses_the_admitted_run_contract(self):
134
+ calls = []
135
+ def transport(method, path, headers, body, query, timeout):
136
+ calls.append((method, path, body))
137
+ return 200, {}, {"id": "run"}
138
+ client = Stacklink(api_key="ppk_test", base_url="http://stacklink.test", transport=transport)
139
+ client.bots.run("bot-one", session_id="session-one", message="Read profile", connection_return_url="https://client.example/connected")
140
+ self.assertEqual(calls[0][2]["connectionReturnUrl"], "https://client.example/connected")
141
+ self.assertEqual(calls[0][2]["sessionId"], "session-one")
142
+
133
143
  def test_bot_management_uses_shared_routes_and_exact_customer_session(self):
134
144
  calls = []
135
145
  def transport(method, path, headers, body, query, timeout):
File without changes
File without changes
File without changes