Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,58 @@ All notable changes to the ChatBotKit Python SDK are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.6.0] - 2026-09-18

### Added

- `token=` is the new name for the API credential, on `ChatBotKit(...)`,
`ClientOptions` and `extend(...)`. `secret=` is deprecated and still works;
`token` wins when both are set.
- `cbk.decision.create` asks a decision model typed questions (boolean,
choice, score) about a state and returns an answer with probabilities for
each. Pass a mapping for choice questions, as the generated `Question` type
cannot hold their named options.

### Changed

- **BREAKING:** skillset ability link fields renamed. On create/update/fetch/
list/export, `secretId` / `fileId` / `botId` / `spaceId` are now
`linkedSecretId` / `linkedFileId` / `linkedBotId` / `linkedSpaceId`. Inline
conversation `extensions.skillsets[].abilities[]` entries use
`linkedSecretId` (and the new `linkedSpaceId`). GraphQL `Ability` relations
`secret` / `file` / `bot` / `space` are now `linkedSecret` / `linkedFile` /
`linkedBot` / `linkedSpace`. There are no compatibility aliases; upgrade
together with the platform deploy.
- Regenerated types also pick up unrelated API changes since the previous
regeneration (2026-08-19), grouped by resource:
- **BREAKING:** Dataset: `store` removed from `DatasetCreateRequest`,
`DatasetFetchResponse`, `DatasetListResponseItem` and
`DatasetListStreamItemData` (the platform now has a single vector store;
the REST API accepts and ignores `store`).
- Conversation: `expiresAt` (epoch ms, auto-delete) added to
`ConversationUpdateRequest`, `ConversationFetchResponse`,
`ConversationListResponseItem` and `ConversationListStreamItemData`.
- Memory: `expiresAt` added to `MemoryCreateRequest`, `MemoryUpdateRequest`,
`MemoryFetchResponse`, `MemoryListResponseItem` and
`MemoryListStreamItemData`.
- Task: `expiresAt` added to `TaskCreateRequest`, `TaskUpdateRequest`,
`TaskFetchResponse`, `TaskListResponseItem` and `TaskListStreamItemData`;
`resumeAt` (when a paused run resumes, null while running) added to
`TaskExecutionListResponseItem` and `TaskExecutionListStreamItemData`.
- Policy: `state` (`enabled` | `disabled`) added to `PolicyCreateRequest`,
`PolicyUpdateRequest`, `PolicyFetchResponse`, `PolicyListResponseItem` and
`PolicyListStreamItemData`.
- WhatsApp integration: `appSecret` (Meta app secret for webhook signature
validation, masked as `********` on read) added to
`IntegrationWhatsAppCreateRequest`, `IntegrationWhatsAppUpdateRequest`,
`IntegrationWhatsAppFetchResponse`, `IntegrationWhatsAppListResponseItem`
and `IntegrationWhatsAppListStreamItemData`; `idempotencyKey` added to
`WhatsappInitiateRequest`.
- GitHub integration: `allowFrom` (allowed senders) added to
`GithubIntegrationCreateRequest`.

## [0.5.1] - 2026-07-22

### Changed
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[![ChatBotKit](https://img.shields.io/badge/credits-ChatBotKit-blue.svg)](https://chatbotkit.com)
[![CBK.AI](https://img.shields.io/badge/credits-CBK.AI-blue.svg)](https://cbk.ai)
[![Email](https://img.shields.io/badge/Email-Support-blue?logo=mail.ru)](mailto:support@chatbotkit.com)
[![Email](https://img.shields.io/badge/Email-Support-blue?logo=mail.ru)](mailto:support@cbk.ai)
[![Discord](https://img.shields.io/badge/Discord-Support-blue?logo=discord)](https://go.cbk.ai/discord)
[![PyPI](https://img.shields.io/pypi/v/chatbotkit.svg)](https://pypi.org/project/chatbotkit/)
[![Follow on Twitter](https://img.shields.io/twitter/follow/chatbotkit.svg?logo=twitter)](https://twitter.com/chatbotkit)
Expand Down Expand Up @@ -39,6 +38,8 @@ This means you can focus on building great user experiences while ChatBotKit han

## Installation

Install the SDK from PyPI with pip:

```bash
pip install chatbotkit
```
Expand Down Expand Up @@ -96,7 +97,7 @@ from chatbotkit.types import ConversationCompleteStreamItemType


async def main():
async with ChatBotKit(secret="your-api-key") as cbk:
async with ChatBotKit(token="your-api-token") as cbk:
completion = cbk.conversation.complete(
None,
{
Expand All @@ -116,13 +117,13 @@ asyncio.run(main())

## SDK Client

Create a client with your API key and access resources as attributes:
Create a client with your API token and access resources as attributes:

```python
from chatbotkit import ChatBotKit

cbk = ChatBotKit(
secret="your-api-key",
token="your-api-token",
base_url="https://api.chatbotkit.com", # optional
run_as_user_id="user-id", # optional
timezone="America/New_York", # optional
Expand All @@ -140,15 +141,15 @@ cbk.blueprint # Blueprint management (cbk.blueprint.resource/bulletin)
cbk.task # Task management (cbk.task.execution)
cbk.team # Team management
cbk.space # Space management (cbk.space.storage)
cbk.partner # Partner management (cbk.partner.user.token)
cbk.user # User management (cbk.user.token)
cbk.policy # Policy management
cbk.portal # Portal management
cbk.usage # Usage reporting (cbk.usage.series)
cbk.magic # Magic AI generation (cbk.magic.prompt)
cbk.event # Event log access (cbk.event.log)
cbk.graphql # GraphQL operations
cbk.channel # Channel publish/subscribe
cbk.platform # Platform content (doc, example, manual, model, tutorial, ...)
cbk.platform # Platform content (doc, example, manual, model, ...)
cbk.integration # Integrations (widget, slack, discord, whatsapp, telegram,
# messenger, instagram, notion, sitemap, support, extract,
# twilio, email, mcp_server, microsoft_teams, google_chat,
Expand Down Expand Up @@ -290,7 +291,7 @@ Options can be passed as keyword arguments or via a `ClientOptions` instance.
```python
from chatbotkit import ChatBotKit, ClientOptions

cbk = ChatBotKit(ClientOptions(secret="your-api-key", timezone="UTC"))
cbk = ChatBotKit(ClientOptions(token="your-api-token", timezone="UTC"))
```

## Error Handling
Expand Down Expand Up @@ -325,7 +326,7 @@ bot = await cbk.bot.create(BotCreateRequest.from_dict({

## Documentation

- **Platform Documentation**: Comprehensive guide to ChatBotKit [here](https://chatbotkit.com/docs).
- **Platform Documentation**: Comprehensive guide to the platform [here](https://docs.cbk.ai/python-sdk).
- **Platform Tutorials**: Step-by-step tutorials for ChatBotKit [here](https://chatbotkit.com/tutorials).

## Contributing
Expand All @@ -337,7 +338,7 @@ Encounter a bug or want to contribute? Open an issue or submit a pull request on
from the latest API specification, run the type sync script from the platform repo:

```bash
pnpm --dir sites/main script:sync-types:python
pnpm --dir platform/platform script:sync-types:python
```

Install the development dependencies and run the test suite with:
Expand Down
2 changes: 1 addition & 1 deletion chatbotkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
"Response",
]

__version__ = "0.5.1"
__version__ = "0.6.0"
6 changes: 4 additions & 2 deletions chatbotkit/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
from .contact import ContactClient
from .conversation import ConversationClient
from .dataset import DatasetClient
from .decision import DecisionClient
from .event import EventClient
from .file import FileClient
from .graphql import GraphqlClient
from .integration import IntegrationClient
from .magic import MagicClient
from .memory import MemoryClient
from .partner import PartnerClient
from .user import UserClient
from .platform import PlatformClient
from .policy import PolicyClient
from .portal import PortalClient
Expand All @@ -34,6 +35,7 @@ def __init__(self, options: ClientOptions | None = None, **kwargs: Any) -> None:
self.bot = BotClient(self)
self.conversation = ConversationClient(self)
self.dataset = DatasetClient(self)
self.decision = DecisionClient(self)
self.skillset = SkillsetClient(self)
self.file = FileClient(self)
self.contact = ContactClient(self)
Expand All @@ -43,7 +45,7 @@ def __init__(self, options: ClientOptions | None = None, **kwargs: Any) -> None:
self.task = TaskClient(self)
self.team = TeamClient(self)
self.space = SpaceClient(self)
self.partner = PartnerClient(self)
self.user = UserClient(self)
self.policy = PolicyClient(self)
self.portal = PortalClient(self)
self.usage = UsageClient(self)
Expand Down
15 changes: 13 additions & 2 deletions chatbotkit/_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class ClientOptions:
headers: Mapping[str, str] | None = None
timeout: float | None = None
transport: httpx.AsyncBaseTransport | None = None
# @note `token` is the name to use; `secret` is its deprecated former name
# and is ignored when `token` is set. It stays last so that positional
# arguments keep their meaning.
token: str | None = None


class APIError(Exception):
Expand Down Expand Up @@ -254,6 +258,11 @@ def __init__(self, options: ClientOptions | None = None, **kwargs: Any) -> None:
)

def extend(self, **kwargs: Any) -> Client:
# @note the deprecated `secret` is folded into `token`, otherwise the
# current token would win over a new credential passed as `secret`
if "secret" in kwargs and "token" not in kwargs:
kwargs = {**kwargs, "token": kwargs["secret"]}

return type(self)(replace(self.options, **kwargs))

async def __aenter__(self) -> Client:
Expand Down Expand Up @@ -431,8 +440,10 @@ def _build_headers(
if has_body:
result["content-type"] = "application/json"

if self.options.secret:
result["authorization"] = f"Bearer {self.options.secret}"
token = self.options.token or self.options.secret

if token:
result["authorization"] = f"Bearer {token}"

if self.options.run_as_user_id:
result["x-runas-user-id"] = self.options.run_as_user_id
Expand Down
28 changes: 28 additions & 0 deletions chatbotkit/decision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from __future__ import annotations

from typing import Any, Mapping

from . import types
from ._transport import Client, Response

Request = Mapping[str, Any]


class DecisionClient:
def __init__(self, client: Client) -> None:
self._client = client

def create(
self,
request: types.DecisionCreateRequest | Request,
) -> Response[types.DecisionCreateResponse, Any]:
"""Answers typed questions about a state.

Pass a mapping for choice questions: the generated ``Question`` type
cannot hold the named options of their ``criteria``.
"""
return self._client.client_fetch(
"/api/v1/decision/create",
record=request,
parse=types.DecisionCreateResponse.from_dict,
)
112 changes: 0 additions & 112 deletions chatbotkit/partner.py

This file was deleted.

Loading
Loading