Skip to content

Commit dc14293

Browse files
authored
Merge pull request #6 from chatbotkit/next
Release python-sdk
2 parents a7cc797 + e63245f commit dc14293

7 files changed

Lines changed: 363 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to the ChatBotKit Python SDK are documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.4.0] - 2026-06-27
8+
9+
### Added
10+
11+
- Secret token minting and request proxying. `client.secret.mint(...)` /
12+
`client.contact.secret.mint(...)` mint a usable token from a secret
13+
(`oauth`/`jwt` secrets only; owner-only) and return `{ token, expiresAt }`.
14+
`client.secret.proxy(...)` / `client.contact.secret.proxy(...)` proxy a request
15+
through a secret — the credential is injected server-side (it never leaves the
16+
platform) and the raw upstream `httpx.Response` is returned verbatim. A non-2xx
17+
status (including `409 authorization_required`) is returned, not raised.
18+
719
## [0.3.0] - 2026-06-26
820

921
### Added

chatbotkit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
"Response",
1010
]
1111

12-
__version__ = "0.3.0"
12+
__version__ = "0.4.0"

chatbotkit/_transport.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ async def request(
252252
record: Any = None,
253253
headers: Mapping[str, str] | None = None,
254254
endpoint: str | None = None,
255+
raw: bool = False,
255256
) -> httpx.Response:
256257
request = self._build_request(
257258
path,
@@ -263,7 +264,11 @@ async def request(
263264
)
264265

265266
response = await self._http.request(**request)
266-
await self.raise_for_status(response)
267+
268+
# in raw (passthrough) mode the caller wants the response verbatim - do
269+
# not raise on a non-2xx status (e.g. the proxy's 409 authorization_required)
270+
if not raw:
271+
await self.raise_for_status(response)
267272

268273
return response
269274

chatbotkit/contact.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from typing import Any, Mapping
44

5+
import httpx
6+
57
from . import types
68
from ._transport import Client, Response
79

@@ -115,6 +117,36 @@ def list(
115117
stream_parse=types.ContactSecretListStreamItem.from_dict,
116118
)
117119

120+
def mint(
121+
self,
122+
contact_id: str,
123+
secret_id: str,
124+
) -> Response[types.ContactSecretMintResponse, Any]:
125+
"""Mint a usable token from a contact's secret (owner-only; oauth/jwt only)."""
126+
return self._client.client_fetch(
127+
f"/api/v1/contact/{contact_id}/secret/{secret_id}/mint",
128+
record={},
129+
parse=types.ContactSecretMintResponse.from_dict,
130+
)
131+
132+
async def proxy(
133+
self,
134+
contact_id: str,
135+
secret_id: str,
136+
request: types.ContactSecretProxyRequest | Request,
137+
) -> httpx.Response:
138+
"""Proxy a request through a contact's secret, injected server-side.
139+
140+
Returns the raw upstream response verbatim; a non-2xx status is returned,
141+
not raised.
142+
"""
143+
return await self._client.request(
144+
f"/api/v1/contact/{contact_id}/secret/{secret_id}/proxy",
145+
method="POST",
146+
record=request,
147+
raw=True,
148+
)
149+
118150

119151
class ContactSpaceClient:
120152
def __init__(self, client: Client) -> None:

chatbotkit/secret.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from typing import Any, Mapping
44

5+
import httpx
6+
57
from . import types
68
from ._transport import Client, Response
79

@@ -60,3 +62,28 @@ def delete(
6062
record=request or {},
6163
parse=types.SecretDeleteResponse.from_dict,
6264
)
65+
66+
def mint(self, secret_id: str) -> Response[types.SecretMintResponse, Any]:
67+
"""Mint a usable token from the secret (owner-only; oauth/jwt only)."""
68+
return self._client.client_fetch(
69+
f"/api/v1/secret/{secret_id}/mint",
70+
record={},
71+
parse=types.SecretMintResponse.from_dict,
72+
)
73+
74+
async def proxy(
75+
self,
76+
secret_id: str,
77+
request: types.SecretProxyRequest | Request,
78+
) -> httpx.Response:
79+
"""Proxy a request through the secret, injected server-side.
80+
81+
Returns the raw upstream response verbatim; a non-2xx status (including
82+
409 authorization_required) is returned, not raised.
83+
"""
84+
return await self._client.request(
85+
f"/api/v1/secret/{secret_id}/proxy",
86+
method="POST",
87+
record=request,
88+
raw=True,
89+
)

0 commit comments

Comments
 (0)