|
1 | | -# Klavis Python Library |
2 | | - |
3 | | -[](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2FKlavis-AI%2Fpython-sdk) |
4 | | -[](https://pypi.python.org/pypi/klavis) |
5 | | - |
6 | | -The Klavis Python library provides convenient access to the Klavis API from Python. |
7 | | - |
8 | | -## Documentation |
9 | | - |
10 | | -The full API of this library can be found in [api.md](api.md). |
11 | | - |
12 | | -## Installation |
13 | | - |
14 | | -```sh |
15 | | -pip install klavis |
16 | | -``` |
17 | | - |
18 | | -## Reference |
19 | | - |
20 | | -A full reference for this library is available [here](https://github.com/Klavis-AI/python-sdk/blob/HEAD/./reference.md). |
21 | | - |
22 | | -## Usage |
23 | | - |
24 | | -Instantiate and use the client with the following: |
25 | | - |
26 | | -```python |
27 | | -from klavis import Klavis |
28 | | - |
29 | | -client = Klavis( |
30 | | - token="YOUR_TOKEN", |
31 | | -) |
32 | | -client.mcp_server.call_server_tool( |
33 | | - server_url="serverUrl", |
34 | | - tool_name="toolName", |
35 | | -) |
36 | | -``` |
37 | | - |
38 | | -## Async Client |
39 | | - |
40 | | -The SDK also exports an `async` client so that you can make non-blocking calls to our API. |
41 | | - |
42 | | -```python |
43 | | -import asyncio |
44 | | - |
45 | | -from klavis import AsyncKlavis |
46 | | - |
47 | | -client = AsyncKlavis( |
48 | | - token="YOUR_TOKEN", |
49 | | -) |
50 | | - |
51 | | - |
52 | | -async def main() -> None: |
53 | | - await client.mcp_server.call_server_tool( |
54 | | - server_url="serverUrl", |
55 | | - tool_name="toolName", |
56 | | - ) |
57 | | - |
58 | | - |
59 | | -asyncio.run(main()) |
60 | | -``` |
61 | | - |
62 | | -## Async usage |
63 | | - |
64 | | -Simply import `AsyncKlavis` instead of `Klavis` and use `await` with each API call: |
65 | | - |
66 | | -```python |
67 | | -import os |
68 | | -import asyncio |
69 | | -from klavis import AsyncKlavis |
70 | | - |
71 | | -client = AsyncKlavis( |
72 | | - api_key=os.environ.get("KLAVIS_API_KEY"), # This is the default and can be omitted |
73 | | -) |
74 | | - |
75 | | - |
76 | | -async def main() -> None: |
77 | | - instance = await client.mcp_server.instance.create( |
78 | | - platform_name="x", |
79 | | - server_name="Markdown2doc", |
80 | | - user_id="x", |
81 | | - ) |
82 | | - print(instance.instance_id) |
83 | | - |
84 | | - |
85 | | -asyncio.run(main()) |
86 | | -``` |
87 | | - |
88 | | -Functionality between the synchronous and asynchronous clients is otherwise identical. |
89 | | - |
90 | | -## Using types |
91 | | - |
92 | | -Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: |
93 | | - |
94 | | -- Serializing back into JSON, `model.to_json()` |
95 | | -- Converting to a dictionary, `model.to_dict()` |
96 | | - |
97 | | -Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. |
98 | | - |
99 | | -## Handling errors |
100 | | - |
101 | | -When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `klavis.APIConnectionError` is raised. |
102 | | - |
103 | | -When the API returns a non-success status code (that is, 4xx or 5xx |
104 | | -response), a subclass of `klavis.APIStatusError` is raised, containing `status_code` and `response` properties. |
105 | | - |
106 | | -All errors inherit from `klavis.APIError`. |
107 | | - |
108 | | -```python |
109 | | -import klavis |
110 | | -from klavis import Klavis |
111 | | - |
112 | | -client = Klavis() |
113 | | - |
114 | | -try: |
115 | | - client.mcp_server.instance.create( |
116 | | - platform_name="x", |
117 | | - server_name="Markdown2doc", |
118 | | - user_id="x", |
119 | | - ) |
120 | | -except klavis.APIConnectionError as e: |
121 | | - print("The server could not be reached") |
122 | | - print(e.__cause__) # an underlying Exception, likely raised within httpx. |
123 | | -except klavis.RateLimitError as e: |
124 | | - print("A 429 status code was received; we should back off a bit.") |
125 | | -except klavis.APIStatusError as e: |
126 | | - print("Another non-200-range status code was received") |
127 | | - print(e.status_code) |
128 | | - print(e.response) |
129 | | -``` |
130 | | - |
131 | | -Error codes are as follows: |
132 | | - |
133 | | -| Status Code | Error Type | |
134 | | -| ----------- | -------------------------- | |
135 | | -| 400 | `BadRequestError` | |
136 | | -| 401 | `AuthenticationError` | |
137 | | -| 403 | `PermissionDeniedError` | |
138 | | -| 404 | `NotFoundError` | |
139 | | -| 422 | `UnprocessableEntityError` | |
140 | | -| 429 | `RateLimitError` | |
141 | | -| >=500 | `InternalServerError` | |
142 | | -| N/A | `APIConnectionError` | |
143 | | - |
144 | | -### Retries |
145 | | - |
146 | | -Certain errors are automatically retried 2 times by default, with a short exponential backoff. |
147 | | -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, |
148 | | -429 Rate Limit, and >=500 Internal errors are all retried by default. |
149 | | - |
150 | | -You can use the `max_retries` option to configure or disable retry settings: |
151 | | - |
152 | | -```python |
153 | | -from klavis import Klavis |
154 | | - |
155 | | -# Configure the default for all requests: |
156 | | -client = Klavis( |
157 | | - # default is 2 |
158 | | - max_retries=0, |
159 | | -) |
160 | | - |
161 | | -# Or, configure per-request: |
162 | | -client.with_options(max_retries=5).mcp_server.instance.create( |
163 | | - platform_name="x", |
164 | | - server_name="Markdown2doc", |
165 | | - user_id="x", |
166 | | -) |
167 | | -``` |
168 | | - |
169 | | -### Timeouts |
170 | | - |
171 | | -By default requests time out after 1 minute. You can configure this with a `timeout` option, |
172 | | -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: |
173 | | - |
174 | | -```python |
175 | | -from klavis import Klavis |
176 | | - |
177 | | -# Configure the default for all requests: |
178 | | -client = Klavis( |
179 | | - # 20 seconds (default is 1 minute) |
180 | | - timeout=20.0, |
181 | | -) |
182 | | - |
183 | | -# More granular control: |
184 | | -client = Klavis( |
185 | | - timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), |
186 | | -) |
187 | | - |
188 | | -# Override per-request: |
189 | | -client.with_options(timeout=5.0).mcp_server.instance.create( |
190 | | - platform_name="x", |
191 | | - server_name="Markdown2doc", |
192 | | - user_id="x", |
193 | | -) |
194 | | -``` |
195 | | - |
196 | | -On timeout, an `APITimeoutError` is thrown. |
197 | | - |
198 | | -Note that requests that time out are [retried twice by default](#retries). |
199 | | - |
200 | | -## Exception Handling |
201 | | - |
202 | | -When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error |
203 | | -will be thrown. |
204 | | - |
205 | | -```python |
206 | | -from klavis.core.api_error import ApiError |
207 | | - |
208 | | -try: |
209 | | - client.mcp_server.call_server_tool(...) |
210 | | -except ApiError as e: |
211 | | - print(e.status_code) |
212 | | - print(e.body) |
213 | | -``` |
214 | | - |
215 | | -## Advanced |
216 | | - |
217 | | -### Access Raw Response Data |
218 | | - |
219 | | -The SDK provides access to raw response data, including headers, through the `.with_raw_response` property. |
220 | | -The `.with_raw_response` property returns a "raw" client that can be used to access the `.headers` and `.data` attributes. |
221 | | - |
222 | | -```python |
223 | | -from klavis import Klavis |
224 | | - |
225 | | -client = Klavis( |
226 | | - ..., |
227 | | -) |
228 | | -response = client.mcp_server.with_raw_response.call_server_tool(...) |
229 | | -print(response.headers) # access the response headers |
230 | | -print(response.data) # access the underlying object |
231 | | -``` |
232 | | - |
233 | | -### Retries |
234 | | - |
235 | | -The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long |
236 | | -as the request is deemed retryable and the number of retry attempts has not grown larger than the configured |
237 | | -retry limit (default: 2). |
238 | | - |
239 | | -A request is deemed retryable when any of the following HTTP status codes is returned: |
240 | | - |
241 | | -- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) |
242 | | -- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) |
243 | | -- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors) |
244 | | - |
245 | | -Use the `max_retries` request option to configure this behavior. |
246 | | - |
247 | | -```python |
248 | | -client.mcp_server.call_server_tool(..., request_options={ |
249 | | - "max_retries": 1 |
250 | | -}) |
251 | | -``` |
252 | | - |
253 | | -### Timeouts |
254 | | - |
255 | | -The SDK defaults to a 60 second timeout. You can configure this with a timeout option at the client or request level. |
256 | | - |
257 | | -```python |
258 | | - |
259 | | -from klavis import Klavis |
260 | | - |
261 | | -client = Klavis( |
262 | | - ..., |
263 | | - timeout=20.0, |
264 | | -) |
265 | | - |
266 | | - |
267 | | -# Override timeout for a specific method |
268 | | -client.mcp_server.call_server_tool(..., request_options={ |
269 | | - "timeout_in_seconds": 1 |
270 | | -}) |
271 | | -``` |
272 | | - |
273 | | -### Custom Client |
274 | | - |
275 | | -You can override the `httpx` client to customize it for your use-case. Some common use-cases include support for proxies |
276 | | -and transports. |
277 | | - |
278 | | -```python |
279 | | -import httpx |
280 | | -from klavis import Klavis |
281 | | - |
282 | | -client = Klavis( |
283 | | - ..., |
284 | | - httpx_client=httpx.Client( |
285 | | - proxies="http://my.test.proxy.example.com", |
286 | | - transport=httpx.HTTPTransport(local_address="0.0.0.0"), |
287 | | - ), |
288 | | -) |
289 | | -``` |
290 | | - |
291 | | -## Contributing |
292 | | - |
293 | | -While we value open-source contributions to this SDK, this library is generated programmatically. |
294 | | -Additions made directly to this library would have to be moved over to our generation code, |
295 | | -otherwise they would be overwritten upon the next generated release. Feel free to open a PR as |
296 | | -a proof of concept, but know that we will not be able to merge it as-is. We suggest opening |
297 | | -an issue first to discuss with us! |
298 | | - |
299 | | -On the other hand, contributions to the README are always very welcome! |
300 | | -## Contributing |
301 | | - |
302 | | -While we value open-source contributions to this SDK, this library is generated programmatically. |
303 | | -Additions made directly to this library would have to be moved over to our generation code, |
304 | | -otherwise they would be overwritten upon the next generated release. Feel free to open a PR as |
305 | | -a proof of concept, but know that we will not be able to merge it as-is. We suggest opening |
306 | | -an issue first to discuss with us! |
307 | | - |
308 | | -On the other hand, contributions to the README are always very welcome! |
309 | | -## Versioning |
310 | | - |
311 | | -This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: |
312 | | - |
313 | | -1. Changes that only affect static types, without breaking runtime behavior. |
314 | | -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ |
315 | | -3. Changes that we do not expect to impact the vast majority of users in practice. |
316 | | - |
317 | | -We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. |
318 | | - |
319 | | -We are keen for your feedback; please open an [issue](https://www.github.com/Klavis-AI/python-sdk/issues) with questions, bugs, or suggestions. |
320 | | - |
321 | | -### Determining the installed version |
322 | | - |
323 | | -If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. |
324 | | - |
325 | | -You can determine the version that is being used at runtime with: |
326 | | - |
327 | | -```py |
328 | | -import klavis |
329 | | -print(klavis.__version__) |
330 | | -``` |
331 | | - |
0 commit comments