getstack 0.16.0__tar.gz → 0.18.0__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 (73) hide show
  1. {getstack-0.16.0 → getstack-0.18.0}/PKG-INFO +1 -1
  2. {getstack-0.16.0 → getstack-0.18.0}/pyproject.toml +1 -1
  3. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/__init__.py +4 -0
  4. getstack-0.18.0/src/getstack/_async/partner_connect.py +43 -0
  5. getstack-0.18.0/src/getstack/_async/usage.py +25 -0
  6. getstack-0.18.0/src/getstack/partner_connect.py +69 -0
  7. getstack-0.18.0/src/getstack/usage.py +55 -0
  8. {getstack-0.16.0 → getstack-0.18.0}/tests/test_parity.py +2 -1
  9. getstack-0.16.0/src/getstack/_async/usage.py +0 -15
  10. getstack-0.16.0/src/getstack/usage.py +0 -37
  11. {getstack-0.16.0 → getstack-0.18.0}/.gitignore +0 -0
  12. {getstack-0.16.0 → getstack-0.18.0}/CLAUDE.md +0 -0
  13. {getstack-0.16.0 → getstack-0.18.0}/LICENSE +0 -0
  14. {getstack-0.16.0 → getstack-0.18.0}/README.md +0 -0
  15. {getstack-0.16.0 → getstack-0.18.0}/scripts/verify_sign_claim_crosslang.py +0 -0
  16. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/__init__.py +0 -0
  17. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/agents.py +0 -0
  18. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/audit.py +0 -0
  19. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/credentials.py +0 -0
  20. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/delivery_methods.py +0 -0
  21. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/detector_config.py +0 -0
  22. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/dropoffs.py +0 -0
  23. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/evidence_packs.py +0 -0
  24. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/identity.py +0 -0
  25. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/inbound_webhooks.py +0 -0
  26. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/intents.py +0 -0
  27. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/llm.py +0 -0
  28. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/missions.py +0 -0
  29. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/notifications.py +0 -0
  30. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/partner_tenants.py +0 -0
  31. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/passport_session.py +0 -0
  32. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/passports.py +0 -0
  33. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/proxy.py +0 -0
  34. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/reviews.py +0 -0
  35. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/scan.py +0 -0
  36. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/security_events.py +0 -0
  37. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/services.py +0 -0
  38. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/skills.py +0 -0
  39. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/_async/team.py +0 -0
  40. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/agent_auth.py +0 -0
  41. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/agents.py +0 -0
  42. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/audit.py +0 -0
  43. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/auth.py +0 -0
  44. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/browser_bootstrap.py +0 -0
  45. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/client.py +0 -0
  46. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/credentials.py +0 -0
  47. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/delivery_methods.py +0 -0
  48. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/detector_config.py +0 -0
  49. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/dropoffs.py +0 -0
  50. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/errors.py +0 -0
  51. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/evidence_packs.py +0 -0
  52. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/identity.py +0 -0
  53. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/inbound_webhooks.py +0 -0
  54. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/intents.py +0 -0
  55. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/llm.py +0 -0
  56. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/missions.py +0 -0
  57. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/notifications.py +0 -0
  58. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/partner_tenants.py +0 -0
  59. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/passport_header_verify.py +0 -0
  60. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/passport_session.py +0 -0
  61. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/passports.py +0 -0
  62. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/proxy.py +0 -0
  63. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/py.typed +0 -0
  64. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/reviews.py +0 -0
  65. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/scan.py +0 -0
  66. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/security_events.py +0 -0
  67. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/services.py +0 -0
  68. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/sign_claim.py +0 -0
  69. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/skills.py +0 -0
  70. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/team.py +0 -0
  71. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/types.py +0 -0
  72. {getstack-0.16.0 → getstack-0.18.0}/src/getstack/verify_offline.py +0 -0
  73. {getstack-0.16.0 → getstack-0.18.0}/tests/test_sign_claim.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getstack
3
- Version: 0.16.0
3
+ Version: 0.18.0
4
4
  Summary: Python SDK for STACK — trust infrastructure for AI agents
5
5
  Project-URL: Homepage, https://getstack.run
6
6
  Project-URL: Documentation, https://getstack.run/docs/sdk
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "getstack"
7
- version = "0.16.0"
7
+ version = "0.18.0"
8
8
  description = "Python SDK for STACK — trust infrastructure for AI agents"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -55,6 +55,7 @@ from .skills import SkillService
55
55
  from .identity import IdentityService
56
56
  from .inbound_webhooks import InboundWebhookService
57
57
  from .partner_tenants import PartnerTenantsService
58
+ from .partner_connect import PartnerConnectService
58
59
  from .passport_header_verify import verify_passport_header
59
60
  from .verify_offline import verify_passport_offline
60
61
  from .sign_claim import sign_claim_envelope
@@ -244,6 +245,7 @@ class Stack:
244
245
  self.llm = LlmService(self._client)
245
246
  self.inbound_webhooks = InboundWebhookService(self._client)
246
247
  self.partner_tenants = PartnerTenantsService(self._client)
248
+ self.partner_connect = PartnerConnectService(self._client)
247
249
  self.team = TeamService(self._client)
248
250
  self.delivery_methods = DeliveryMethodService(self._client)
249
251
  self.detector_config = DetectorConfigService(self._client)
@@ -389,6 +391,7 @@ class AsyncStack:
389
391
  from ._async.llm import AsyncLlmService
390
392
  from ._async.inbound_webhooks import AsyncInboundWebhookService
391
393
  from ._async.partner_tenants import AsyncPartnerTenantsService
394
+ from ._async.partner_connect import AsyncPartnerConnectService
392
395
  from ._async.evidence_packs import AsyncEvidencePacksService
393
396
  from ._async.team import AsyncTeamService
394
397
  from ._async.delivery_methods import AsyncDeliveryMethodService
@@ -414,6 +417,7 @@ class AsyncStack:
414
417
  self.llm = AsyncLlmService(self._client)
415
418
  self.inbound_webhooks = AsyncInboundWebhookService(self._client)
416
419
  self.partner_tenants = AsyncPartnerTenantsService(self._client)
420
+ self.partner_connect = AsyncPartnerConnectService(self._client)
417
421
  self.evidence_packs = AsyncEvidencePacksService(self._client)
418
422
  self.team = AsyncTeamService(self._client)
419
423
  self.delivery_methods = AsyncDeliveryMethodService(self._client)
@@ -0,0 +1,43 @@
1
+ """Async mirror of PartnerConnectService (GET-210)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+ from ..client import AsyncHttpClient
8
+
9
+
10
+ class AsyncPartnerConnectService:
11
+ def __init__(self, client: AsyncHttpClient):
12
+ self._client = client
13
+
14
+ async def connect(
15
+ self,
16
+ email: str,
17
+ external_customer_id: Optional[str] = None,
18
+ scopes: Optional[list[str]] = None,
19
+ providers: Optional[list[str]] = None,
20
+ ) -> dict[str, Any]:
21
+ body: dict[str, Any] = {"email": email}
22
+ if external_customer_id is not None:
23
+ body["external_customer_id"] = external_customer_id
24
+ if scopes is not None:
25
+ body["scopes"] = scopes
26
+ if providers is not None:
27
+ body["providers"] = providers
28
+ return await self._client.post("/v1/partner/connect", json=body)
29
+
30
+ async def list_connections(self) -> list[dict[str, Any]]:
31
+ res = await self._client.get("/v1/partner/connections")
32
+ return list(res.get("connections", []))
33
+
34
+ async def get_connection(self, grant_id: str) -> dict[str, Any]:
35
+ return await self._client.get(f"/v1/partner/connections/{grant_id}")
36
+
37
+ async def revoke_connection(self, grant_id: str) -> dict[str, Any]:
38
+ return await self._client.delete(f"/v1/partner/connections/{grant_id}")
39
+
40
+ async def rotate_token(self, grant_id: str) -> dict[str, Any]:
41
+ return await self._client.post(
42
+ f"/v1/partner/connections/{grant_id}/rotate-token", json={}
43
+ )
@@ -0,0 +1,25 @@
1
+ """Async mirror of UsageService."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from ..client import AsyncHttpClient
8
+
9
+
10
+ class AsyncUsageService:
11
+ def __init__(self, client: AsyncHttpClient):
12
+ self._client = client
13
+
14
+ async def get(
15
+ self,
16
+ *,
17
+ since: str | None = None,
18
+ until: str | None = None,
19
+ ) -> dict[str, Any]:
20
+ params: dict[str, str] = {}
21
+ if since is not None:
22
+ params["since"] = since
23
+ if until is not None:
24
+ params["until"] = until
25
+ return await self._client.get("/v1/usage", params=params or None)
@@ -0,0 +1,69 @@
1
+ """GET-210 — "Connect with STACK" partner surface (sync).
2
+
3
+ connect(email) creates a USER-OWNED STACK account on the customer's
4
+ real email (Express model, notice email) or opens a consent flow when
5
+ the account exists, and returns an opaque ``sk_grant_*`` token you
6
+ attach to the calls you already make — same Bearer header, scoped to
7
+ what the grant created, revocable by the user under /services.
8
+
9
+ Supersedes the Phase 5.6 child-tenant OWNERSHIP semantics; the tenant
10
+ surface remains available through its deprecation window.
11
+
12
+ Near-zero integration::
13
+
14
+ res = stack.partner_connect.connect(email="customer@example.com")
15
+ user_stack = Stack(api_key=res["grant_token"])
16
+ # register agents, connect your provider, issue passports, proxy.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from typing import Any, Optional
22
+
23
+ from .client import HttpClient
24
+
25
+
26
+ class PartnerConnectService:
27
+ def __init__(self, client: HttpClient):
28
+ self._client = client
29
+
30
+ def connect(
31
+ self,
32
+ email: str,
33
+ external_customer_id: Optional[str] = None,
34
+ scopes: Optional[list[str]] = None,
35
+ providers: Optional[list[str]] = None,
36
+ ) -> dict[str, Any]:
37
+ """One call: create-on-email or consent-request.
38
+
39
+ The response's ``grant_token`` is present EXACTLY ONCE, on the
40
+ call that created the grant. ``status`` is ``active`` (new
41
+ account) or ``pending_consent`` (existing account — the token
42
+ authenticates nothing until the user approves).
43
+ """
44
+ body: dict[str, Any] = {"email": email}
45
+ if external_customer_id is not None:
46
+ body["external_customer_id"] = external_customer_id
47
+ if scopes is not None:
48
+ body["scopes"] = scopes
49
+ if providers is not None:
50
+ body["providers"] = providers
51
+ return self._client.post("/v1/partner/connect", json=body)
52
+
53
+ def list_connections(self) -> list[dict[str, Any]]:
54
+ res = self._client.get("/v1/partner/connections")
55
+ return list(res.get("connections", []))
56
+
57
+ def get_connection(self, grant_id: str) -> dict[str, Any]:
58
+ return self._client.get(f"/v1/partner/connections/{grant_id}")
59
+
60
+ def revoke_connection(self, grant_id: str) -> dict[str, Any]:
61
+ """Revoke the edge. Cascades: grant-created agents' passports,
62
+ webhooks, and connections all die with it."""
63
+ return self._client.delete(f"/v1/partner/connections/{grant_id}")
64
+
65
+ def rotate_token(self, grant_id: str) -> dict[str, Any]:
66
+ """Rotate the grant token (lost/leaked). New plaintext returned once."""
67
+ return self._client.post(
68
+ f"/v1/partner/connections/{grant_id}/rotate-token", json={}
69
+ )
@@ -0,0 +1,55 @@
1
+ """Usage service — `/v1/usage` (usage + spend + earnings rollup).
2
+
3
+ The one-call rollup of what your operator consumed against its plan,
4
+ spent, and earned this billing period. Superset of the per-domain meters
5
+ (`stack.scan.usage()`, `stack.llm.usage`, `stack.proxy` counts) — one
6
+ authoritative shape the CLI and dashboard read too. Money fields are in
7
+ cents.
8
+
9
+ Example::
10
+
11
+ u = stack.usage.get()
12
+ p = u["consumption"]["passports"]
13
+ print(f"Passports {p['used']}/{p['limit']}")
14
+ print(f"Spent this period: ${u['spend_cents']['total'] / 100:.2f}")
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Any
20
+
21
+ from .client import HttpClient
22
+
23
+
24
+ class UsageService:
25
+ def __init__(self, client: HttpClient):
26
+ self._client = client
27
+
28
+ def get(
29
+ self,
30
+ *,
31
+ since: str | None = None,
32
+ until: str | None = None,
33
+ ) -> dict[str, Any]:
34
+ """Usage, spend, and earnings for the current billing period.
35
+
36
+ Args:
37
+ since: Optional window start (ISO-8601 or unix-ms). When set, the
38
+ flow metrics (spend, passports, dropoffs, skill invocations,
39
+ proxy) are scoped to the window; inventory meters gain a
40
+ ``created_in_window`` count. Omit for the billing period.
41
+ until: Optional exclusive window end.
42
+
43
+ Returns:
44
+ Dict with keys: tier, period_start, period_end, period_label,
45
+ consumption (per-meter {used, limit, created_in_window?}),
46
+ spend_cents (skills / llm_compute / identity / overage / total),
47
+ wallet_cents ({balance}), and earnings_cents ({unpaid, lifetime}).
48
+ All money in cents.
49
+ """
50
+ params: dict[str, str] = {}
51
+ if since is not None:
52
+ params["since"] = since
53
+ if until is not None:
54
+ params["until"] = until
55
+ return self._client.get("/v1/usage", params=params or None)
@@ -34,7 +34,8 @@ EXPECTED_SERVICES = [
34
34
  "agents", "passports", "credentials", "services", "dropoffs", "reviews",
35
35
  "notifications", "audit", "proxy", "scan", "usage", "security_events",
36
36
  "skills", "identity", "intents", "missions", "evidence_packs", "llm",
37
- "inbound_webhooks", "partner_tenants", "team", "delivery_methods",
37
+ "inbound_webhooks", "partner_tenants",
38
+ "partner_connect", "team", "delivery_methods",
38
39
  "detector_config",
39
40
  ]
40
41
 
@@ -1,15 +0,0 @@
1
- """Async mirror of UsageService."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import Any
6
-
7
- from ..client import AsyncHttpClient
8
-
9
-
10
- class AsyncUsageService:
11
- def __init__(self, client: AsyncHttpClient):
12
- self._client = client
13
-
14
- async def get(self) -> dict[str, Any]:
15
- return await self._client.request("GET", "/v1/usage")
@@ -1,37 +0,0 @@
1
- """Usage service — `/v1/usage` (usage + spend + earnings rollup).
2
-
3
- The one-call rollup of what your operator consumed against its plan,
4
- spent, and earned this billing period. Superset of the per-domain meters
5
- (`stack.scan.usage()`, `stack.llm.usage`, `stack.proxy` counts) — one
6
- authoritative shape the CLI and dashboard read too. Money fields are in
7
- cents.
8
-
9
- Example::
10
-
11
- u = stack.usage.get()
12
- p = u["consumption"]["passports"]
13
- print(f"Passports {p['used']}/{p['limit']}")
14
- print(f"Spent this period: ${u['spend_cents']['total'] / 100:.2f}")
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- from typing import Any
20
-
21
- from .client import HttpClient
22
-
23
-
24
- class UsageService:
25
- def __init__(self, client: HttpClient):
26
- self._client = client
27
-
28
- def get(self) -> dict[str, Any]:
29
- """Usage, spend, and earnings for the current billing period.
30
-
31
- Returns:
32
- Dict with keys: tier, period_start, period_end, consumption
33
- (per-meter {used, limit}), spend_cents (skills / llm_compute /
34
- identity / overage / total), wallet_cents ({balance}), and
35
- earnings_cents ({unpaid, lifetime}). All money in cents.
36
- """
37
- return self._client.request("GET", "/v1/usage")
File without changes
File without changes
File without changes
File without changes
File without changes