wizchat-management 1.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WizChat (Originn Ltd.)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: wizchat-management
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the WizChat Management API (config-as-code control plane).
5
+ Author: WizChat
6
+ License: MIT
7
+ Keywords: wizchat,chatbot,management,config-as-code,sdk
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: httpx>=0.27
21
+ Requires-Dist: pydantic>=2
22
+ Provides-Extra: dev
23
+ Requires-Dist: datamodel-code-generator>=0.25; extra == "dev"
24
+ Requires-Dist: pytest>=7; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # wizchat-management
28
+
29
+ Official Python SDK for the **WizChat Management API** — the programmatic
30
+ control plane for WizChat chatbots, including the config-as-code workflow
31
+ (`get_config` → edit → `apply_config`).
32
+
33
+ The typed models in `wizchat_management.models` are generated from the canonical
34
+ OpenAPI 3.1 document via [`datamodel-code-generator`](https://github.com/koxudaxi/datamodel-code-generator)
35
+ (Pydantic v2). The client is a thin [`httpx`](https://www.python-httpx.org/)
36
+ wrapper — no heavy framework dependencies. It mirrors the TypeScript SDK
37
+ (`@wizchat/management`) one-to-one in surface and semantics.
38
+
39
+ ## Install
40
+
41
+ ```bash
42
+ pip install wizchat-management
43
+ ```
44
+
45
+ Requires Python 3.10+.
46
+
47
+ ## Authentication
48
+
49
+ Authenticate with a Management API key (`wpk_live_…`). It is sent on every
50
+ request as `Authorization: Bearer <key>`. Keys are **scoped** — each operation
51
+ requires specific scopes (`chatbots:read`, `chatbots:write`, `mcp:*`,
52
+ `skills:*`, `security:*`, `domains:*`, `deploy`, `analytics:read`,
53
+ `documents:*`, `videos:*`). A request with insufficient scope raises a
54
+ `WizChatApiError` (`status == 403`, `code == "insufficient_scope"`).
55
+
56
+ ```python
57
+ import os
58
+ from wizchat_management import WizChatClient
59
+
60
+ wizchat = WizChatClient(
61
+ api_key=os.environ["WIZCHAT_API_KEY"], # wpk_live_...
62
+ # base_url defaults to https://www.wizchat.com — override for staging/self-host.
63
+ )
64
+ ```
65
+
66
+ ## Quickstart
67
+
68
+ ```python
69
+ import os
70
+ from wizchat_management import WizChatClient, WizChatApiError
71
+
72
+ wizchat = WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"])
73
+
74
+ try:
75
+ # 1. List your chatbots.
76
+ chatbots = wizchat.list_chatbots()
77
+ chatbot_id = chatbots[0].id
78
+
79
+ # 2. Export the current configuration as a desired-state document.
80
+ config = wizchat.get_config(chatbot_id)
81
+
82
+ # 3. Edit the document in memory (config-as-code).
83
+ core = dict(config.spec.core or {})
84
+ core["name"] = "Acme Support Bot"
85
+ config.spec.core = core
86
+
87
+ # 4. Preview the change with a dry-run — returns the reconcile plan, no writes.
88
+ plan = wizchat.apply_config(chatbot_id, config, dry_run=True)
89
+ print(plan.plan.summary) # { create, update, delete, noop }
90
+
91
+ # 5. Apply for real once the plan looks right.
92
+ result = wizchat.apply_config(chatbot_id, config)
93
+ print(result.applied)
94
+ except WizChatApiError as err:
95
+ print(f"API error {err.status} [{err.code}]: {err.message}", err.details)
96
+ finally:
97
+ wizchat.close()
98
+ ```
99
+
100
+ `WizChatClient` is also a context manager, which closes the connection pool for
101
+ you:
102
+
103
+ ```python
104
+ with WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"]) as wizchat:
105
+ chatbots = wizchat.list_chatbots()
106
+ ```
107
+
108
+ ### Partial-failure semantics (HTTP 422)
109
+
110
+ `apply_config` returns an `ApplyResult` for **both** full success (HTTP 200) and
111
+ **partial failure (HTTP 422)** — a 422 is *not* raised. The body is an
112
+ `ApplyResult` (`applied` / `failed` / `plan`), not an error envelope. Inspect
113
+ `result.failed` (`None` when everything applied) and re-apply after fixing the
114
+ offending section — apply is idempotent:
115
+
116
+ ```python
117
+ result = wizchat.apply_config(chatbot_id, config)
118
+ if result.failed is not None:
119
+ print("section failed:", result.failed.op, result.failed.message)
120
+ # fix the offending section, then re-apply (idempotent)
121
+ ```
122
+
123
+ Auth/validation failures (400/401/403/404/429) still raise `WizChatApiError`.
124
+
125
+ ### Prune semantics
126
+
127
+ `apply` defaults to `prune=true` — array sections (`mcpServers`, `skills`,
128
+ `domains`) are **authoritative**: resources present on the chatbot but absent
129
+ from the document are **deleted**. Every delete is surfaced in the dry-run plan
130
+ first. Pass `prune=False` for merge-only (create/update, never delete):
131
+
132
+ ```python
133
+ wizchat.apply_config(chatbot_id, config, prune=False)
134
+ ```
135
+
136
+ `dry_run` is sent **only** as the `?dryRun=true` query param; any stray `dryRun`
137
+ on the document body is stripped so the per-call option is the single source of
138
+ truth.
139
+
140
+ ## Ergonomic helpers
141
+
142
+ | Method | HTTP | Scope |
143
+ |---|---|---|
144
+ | `list_chatbots()` | `GET /api/v1/chatbots` | `chatbots:read` |
145
+ | `get_chatbot(chatbot_id)` | `GET /api/v1/chatbots/{id}` | `chatbots:read` |
146
+ | `get_config(chatbot_id)` | `GET /api/v1/chatbots/{id}/config` | `chatbots:read` (+ per-section read) |
147
+ | `apply_config(chatbot_id, document, *, dry_run=False, prune=None)` | `POST /api/v1/chatbots/{id}/apply` | per-section read (dry-run) / write (apply) |
148
+
149
+ Each helper returns a typed Pydantic model (or list) and raises
150
+ `WizChatApiError` on a non-2xx response (except the documented 422 on apply).
151
+
152
+ ## Errors
153
+
154
+ ```python
155
+ class WizChatApiError(Exception):
156
+ status: int # HTTP status (401, 403, 404, 422, 429, …)
157
+ code: str # e.g. "not_found", "insufficient_scope"
158
+ message: str # human-readable
159
+ details: dict | None # optional structured context
160
+ ```
161
+
162
+ When the body is not the standard `{ "error": { code, message, details } }`
163
+ envelope, `code` falls back to `http_<status>`.
164
+
165
+ ## Generated models
166
+
167
+ All request/response payloads are typed by Pydantic v2 models in
168
+ `wizchat_management.models`, generated from the OpenAPI components. The key
169
+ types are re-exported from the package root:
170
+
171
+ ```python
172
+ from wizchat_management import (
173
+ ChatbotConfigDocument,
174
+ ApplyResult,
175
+ Plan,
176
+ PublicChatbot,
177
+ Spec,
178
+ )
179
+ ```
180
+
181
+ Less-common types (e.g. `PublicMcpServer`, `PublicSkill`, `PublicTelemetry`)
182
+ live in `wizchat_management.models`.
183
+
184
+ ## Development
185
+
186
+ The models are generated from the **single committed OpenAPI snapshot** shared
187
+ with the TypeScript SDK (`sdks/typescript/openapi.json`) — there is no second
188
+ copy under `sdks/python`.
189
+
190
+ ```bash
191
+ python -m venv .venv
192
+ .venv/Scripts/activate # Windows (POSIX: source .venv/bin/activate)
193
+ pip install -e ".[dev]"
194
+
195
+ python scripts/gen.py # regenerate wizchat_management/models.py
196
+ pytest # run the httpx-MockTransport suite
197
+ ```
198
+
199
+ `scripts/gen.py` runs:
200
+
201
+ ```bash
202
+ datamodel-codegen \
203
+ --input ../typescript/openapi.json --input-file-type openapi \
204
+ --output wizchat_management/models.py \
205
+ --output-model-type pydantic_v2.BaseModel \
206
+ --openapi-scopes schemas --use-annotated --field-constraints \
207
+ --use-standard-collections --target-python-version 3.10 \
208
+ --disable-timestamp --collapse-root-models --formatters black isort
209
+ ```
210
+
211
+ Re-running is deterministic for a fixed input snapshot. The package version
212
+ tracks the OpenAPI `info.version`.
@@ -0,0 +1,186 @@
1
+ # wizchat-management
2
+
3
+ Official Python SDK for the **WizChat Management API** — the programmatic
4
+ control plane for WizChat chatbots, including the config-as-code workflow
5
+ (`get_config` → edit → `apply_config`).
6
+
7
+ The typed models in `wizchat_management.models` are generated from the canonical
8
+ OpenAPI 3.1 document via [`datamodel-code-generator`](https://github.com/koxudaxi/datamodel-code-generator)
9
+ (Pydantic v2). The client is a thin [`httpx`](https://www.python-httpx.org/)
10
+ wrapper — no heavy framework dependencies. It mirrors the TypeScript SDK
11
+ (`@wizchat/management`) one-to-one in surface and semantics.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install wizchat-management
17
+ ```
18
+
19
+ Requires Python 3.10+.
20
+
21
+ ## Authentication
22
+
23
+ Authenticate with a Management API key (`wpk_live_…`). It is sent on every
24
+ request as `Authorization: Bearer <key>`. Keys are **scoped** — each operation
25
+ requires specific scopes (`chatbots:read`, `chatbots:write`, `mcp:*`,
26
+ `skills:*`, `security:*`, `domains:*`, `deploy`, `analytics:read`,
27
+ `documents:*`, `videos:*`). A request with insufficient scope raises a
28
+ `WizChatApiError` (`status == 403`, `code == "insufficient_scope"`).
29
+
30
+ ```python
31
+ import os
32
+ from wizchat_management import WizChatClient
33
+
34
+ wizchat = WizChatClient(
35
+ api_key=os.environ["WIZCHAT_API_KEY"], # wpk_live_...
36
+ # base_url defaults to https://www.wizchat.com — override for staging/self-host.
37
+ )
38
+ ```
39
+
40
+ ## Quickstart
41
+
42
+ ```python
43
+ import os
44
+ from wizchat_management import WizChatClient, WizChatApiError
45
+
46
+ wizchat = WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"])
47
+
48
+ try:
49
+ # 1. List your chatbots.
50
+ chatbots = wizchat.list_chatbots()
51
+ chatbot_id = chatbots[0].id
52
+
53
+ # 2. Export the current configuration as a desired-state document.
54
+ config = wizchat.get_config(chatbot_id)
55
+
56
+ # 3. Edit the document in memory (config-as-code).
57
+ core = dict(config.spec.core or {})
58
+ core["name"] = "Acme Support Bot"
59
+ config.spec.core = core
60
+
61
+ # 4. Preview the change with a dry-run — returns the reconcile plan, no writes.
62
+ plan = wizchat.apply_config(chatbot_id, config, dry_run=True)
63
+ print(plan.plan.summary) # { create, update, delete, noop }
64
+
65
+ # 5. Apply for real once the plan looks right.
66
+ result = wizchat.apply_config(chatbot_id, config)
67
+ print(result.applied)
68
+ except WizChatApiError as err:
69
+ print(f"API error {err.status} [{err.code}]: {err.message}", err.details)
70
+ finally:
71
+ wizchat.close()
72
+ ```
73
+
74
+ `WizChatClient` is also a context manager, which closes the connection pool for
75
+ you:
76
+
77
+ ```python
78
+ with WizChatClient(api_key=os.environ["WIZCHAT_API_KEY"]) as wizchat:
79
+ chatbots = wizchat.list_chatbots()
80
+ ```
81
+
82
+ ### Partial-failure semantics (HTTP 422)
83
+
84
+ `apply_config` returns an `ApplyResult` for **both** full success (HTTP 200) and
85
+ **partial failure (HTTP 422)** — a 422 is *not* raised. The body is an
86
+ `ApplyResult` (`applied` / `failed` / `plan`), not an error envelope. Inspect
87
+ `result.failed` (`None` when everything applied) and re-apply after fixing the
88
+ offending section — apply is idempotent:
89
+
90
+ ```python
91
+ result = wizchat.apply_config(chatbot_id, config)
92
+ if result.failed is not None:
93
+ print("section failed:", result.failed.op, result.failed.message)
94
+ # fix the offending section, then re-apply (idempotent)
95
+ ```
96
+
97
+ Auth/validation failures (400/401/403/404/429) still raise `WizChatApiError`.
98
+
99
+ ### Prune semantics
100
+
101
+ `apply` defaults to `prune=true` — array sections (`mcpServers`, `skills`,
102
+ `domains`) are **authoritative**: resources present on the chatbot but absent
103
+ from the document are **deleted**. Every delete is surfaced in the dry-run plan
104
+ first. Pass `prune=False` for merge-only (create/update, never delete):
105
+
106
+ ```python
107
+ wizchat.apply_config(chatbot_id, config, prune=False)
108
+ ```
109
+
110
+ `dry_run` is sent **only** as the `?dryRun=true` query param; any stray `dryRun`
111
+ on the document body is stripped so the per-call option is the single source of
112
+ truth.
113
+
114
+ ## Ergonomic helpers
115
+
116
+ | Method | HTTP | Scope |
117
+ |---|---|---|
118
+ | `list_chatbots()` | `GET /api/v1/chatbots` | `chatbots:read` |
119
+ | `get_chatbot(chatbot_id)` | `GET /api/v1/chatbots/{id}` | `chatbots:read` |
120
+ | `get_config(chatbot_id)` | `GET /api/v1/chatbots/{id}/config` | `chatbots:read` (+ per-section read) |
121
+ | `apply_config(chatbot_id, document, *, dry_run=False, prune=None)` | `POST /api/v1/chatbots/{id}/apply` | per-section read (dry-run) / write (apply) |
122
+
123
+ Each helper returns a typed Pydantic model (or list) and raises
124
+ `WizChatApiError` on a non-2xx response (except the documented 422 on apply).
125
+
126
+ ## Errors
127
+
128
+ ```python
129
+ class WizChatApiError(Exception):
130
+ status: int # HTTP status (401, 403, 404, 422, 429, …)
131
+ code: str # e.g. "not_found", "insufficient_scope"
132
+ message: str # human-readable
133
+ details: dict | None # optional structured context
134
+ ```
135
+
136
+ When the body is not the standard `{ "error": { code, message, details } }`
137
+ envelope, `code` falls back to `http_<status>`.
138
+
139
+ ## Generated models
140
+
141
+ All request/response payloads are typed by Pydantic v2 models in
142
+ `wizchat_management.models`, generated from the OpenAPI components. The key
143
+ types are re-exported from the package root:
144
+
145
+ ```python
146
+ from wizchat_management import (
147
+ ChatbotConfigDocument,
148
+ ApplyResult,
149
+ Plan,
150
+ PublicChatbot,
151
+ Spec,
152
+ )
153
+ ```
154
+
155
+ Less-common types (e.g. `PublicMcpServer`, `PublicSkill`, `PublicTelemetry`)
156
+ live in `wizchat_management.models`.
157
+
158
+ ## Development
159
+
160
+ The models are generated from the **single committed OpenAPI snapshot** shared
161
+ with the TypeScript SDK (`sdks/typescript/openapi.json`) — there is no second
162
+ copy under `sdks/python`.
163
+
164
+ ```bash
165
+ python -m venv .venv
166
+ .venv/Scripts/activate # Windows (POSIX: source .venv/bin/activate)
167
+ pip install -e ".[dev]"
168
+
169
+ python scripts/gen.py # regenerate wizchat_management/models.py
170
+ pytest # run the httpx-MockTransport suite
171
+ ```
172
+
173
+ `scripts/gen.py` runs:
174
+
175
+ ```bash
176
+ datamodel-codegen \
177
+ --input ../typescript/openapi.json --input-file-type openapi \
178
+ --output wizchat_management/models.py \
179
+ --output-model-type pydantic_v2.BaseModel \
180
+ --openapi-scopes schemas --use-annotated --field-constraints \
181
+ --use-standard-collections --target-python-version 3.10 \
182
+ --disable-timestamp --collapse-root-models --formatters black isort
183
+ ```
184
+
185
+ Re-running is deterministic for a fixed input snapshot. The package version
186
+ tracks the OpenAPI `info.version`.
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wizchat-management"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for the WizChat Management API (config-as-code control plane)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "WizChat" }]
13
+ keywords = ["wizchat", "chatbot", "management", "config-as-code", "sdk"]
14
+ dependencies = [
15
+ "httpx>=0.27",
16
+ "pydantic>=2",
17
+ ]
18
+ classifiers = [
19
+ "License :: OSI Approved :: MIT License",
20
+ "Development Status :: 4 - Beta",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Typing :: Typed",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "datamodel-code-generator>=0.25",
33
+ "pytest>=7",
34
+ ]
35
+
36
+ [tool.setuptools]
37
+ packages = ["wizchat_management"]
38
+
39
+ [tool.setuptools.package-data]
40
+ wizchat_management = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+