notte-sdk 0.0.dev0__py3-none-any.whl

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,542 @@
1
+ from collections.abc import Sequence
2
+ from pathlib import Path
3
+ from typing import Unpack
4
+ from webbrowser import open as open_browser
5
+
6
+ from loguru import logger
7
+ from notte_core.browser.observation import Observation
8
+ from notte_core.common.resource import SyncResource
9
+ from notte_core.data.space import DataSpace
10
+ from notte_core.utils.webp_replay import WebpReplay
11
+ from pydantic import BaseModel
12
+ from typing_extensions import final, override
13
+
14
+ from notte_sdk.endpoints.base import BaseClient, NotteEndpoint
15
+ from notte_sdk.endpoints.page import PageClient
16
+ from notte_sdk.types import (
17
+ ListRequestDict,
18
+ ObserveRequestDict,
19
+ SessionDebugResponse,
20
+ SessionListRequest,
21
+ SessionResponse,
22
+ SessionStartRequest,
23
+ SessionStartRequestDict,
24
+ StepRequestDict,
25
+ TabSessionDebugRequest,
26
+ TabSessionDebugResponse,
27
+ UploadCookiesRequest,
28
+ UploadCookiesResponse,
29
+ )
30
+ from notte_sdk.websockets.recording import SessionRecordingWebSocket
31
+
32
+
33
+ @final
34
+ class SessionsClient(BaseClient):
35
+ """
36
+ Client for the Notte API.
37
+
38
+ Note: this client is only able to handle one session at a time.
39
+ If you need to handle multiple sessions, you need to create a new client for each session.
40
+ """
41
+
42
+ # Session
43
+ SESSION_START = "start"
44
+ SESSION_STOP = "{session_id}/stop"
45
+ SESSION_STATUS = "{session_id}"
46
+ SESSION_LIST = ""
47
+ # upload cookies
48
+ SESSION_UPLOAD_FILES_COOKIES = "cookies"
49
+ # Session Debug
50
+ SESSION_DEBUG = "{session_id}/debug"
51
+ SESSION_DEBUG_TAB = "{session_id}/debug/tab"
52
+ SESSION_DEBUG_REPLAY = "{session_id}/replay"
53
+
54
+ def __init__(
55
+ self,
56
+ api_key: str | None = None,
57
+ verbose: bool = False,
58
+ ):
59
+ """
60
+ Initialize a SessionsClient instance.
61
+
62
+ Initializes the client with an optional API key and server URL for session management,
63
+ setting the base endpoint to "sessions". Also initializes the last session response to None.
64
+ """
65
+ super().__init__(base_endpoint_path="sessions", api_key=api_key, verbose=verbose)
66
+ self.page: PageClient = PageClient(api_key=api_key, verbose=verbose)
67
+
68
+ @staticmethod
69
+ def session_start_endpoint() -> NotteEndpoint[SessionResponse]:
70
+ """
71
+ Returns a NotteEndpoint configured for starting a session.
72
+
73
+ The returned endpoint uses the session start path from SessionsClient with the POST method and expects a SessionResponse.
74
+ """
75
+ return NotteEndpoint(path=SessionsClient.SESSION_START, response=SessionResponse, method="POST")
76
+
77
+ @staticmethod
78
+ def session_stop_endpoint(session_id: str | None = None) -> NotteEndpoint[SessionResponse]:
79
+ """
80
+ Constructs a DELETE endpoint for closing a session.
81
+
82
+ If a session ID is provided, it is inserted into the endpoint path. Returns a NotteEndpoint configured
83
+ with the DELETE method and expecting a SessionResponse.
84
+
85
+ Args:
86
+ session_id: Optional session identifier; if provided, it is formatted into the endpoint path.
87
+
88
+ Returns:
89
+ A NotteEndpoint instance for closing a session.
90
+ """
91
+ path = SessionsClient.SESSION_STOP
92
+ if session_id is not None:
93
+ path = path.format(session_id=session_id)
94
+ return NotteEndpoint(path=path, response=SessionResponse, method="DELETE")
95
+
96
+ @staticmethod
97
+ def session_status_endpoint(session_id: str | None = None) -> NotteEndpoint[SessionResponse]:
98
+ """
99
+ Returns a NotteEndpoint for retrieving the status of a session.
100
+
101
+ If a session_id is provided, it is interpolated into the endpoint path.
102
+ The endpoint uses the GET method and expects a SessionResponse.
103
+ """
104
+ path = SessionsClient.SESSION_STATUS
105
+ if session_id is not None:
106
+ path = path.format(session_id=session_id)
107
+ return NotteEndpoint(path=path, response=SessionResponse, method="GET")
108
+
109
+ @staticmethod
110
+ def session_list_endpoint(params: SessionListRequest | None = None) -> NotteEndpoint[SessionResponse]:
111
+ """
112
+ Constructs a NotteEndpoint for listing sessions.
113
+
114
+ Args:
115
+ params (SessionListRequest, optional): Additional filter parameters for the session list request.
116
+
117
+ Returns:
118
+ NotteEndpoint[SessionResponse]: An endpoint configured with the session list path and a GET method.
119
+ """
120
+ return NotteEndpoint(
121
+ path=SessionsClient.SESSION_LIST,
122
+ response=SessionResponse,
123
+ method="GET",
124
+ request=None,
125
+ params=params,
126
+ )
127
+
128
+ @staticmethod
129
+ def session_debug_endpoint(session_id: str | None = None) -> NotteEndpoint[SessionDebugResponse]:
130
+ """
131
+ Creates a NotteEndpoint for retrieving session debug information.
132
+
133
+ If a session ID is provided, it is interpolated into the endpoint path.
134
+ The returned endpoint uses the GET method and expects a SessionDebugResponse.
135
+ """
136
+ path = SessionsClient.SESSION_DEBUG
137
+ if session_id is not None:
138
+ path = path.format(session_id=session_id)
139
+ return NotteEndpoint(path=path, response=SessionDebugResponse, method="GET")
140
+
141
+ @staticmethod
142
+ def session_debug_tab_endpoint(
143
+ session_id: str | None = None, params: TabSessionDebugRequest | None = None
144
+ ) -> NotteEndpoint[TabSessionDebugResponse]:
145
+ """
146
+ Returns an endpoint for retrieving debug information for a session tab.
147
+
148
+ If a session ID is provided, it is substituted in the URL path.
149
+ Additional query parameters can be specified via the params argument.
150
+
151
+ Returns:
152
+ NotteEndpoint[TabSessionDebugResponse]: The configured endpoint for a GET request.
153
+ """
154
+ path = SessionsClient.SESSION_DEBUG_TAB
155
+ if session_id is not None:
156
+ path = path.format(session_id=session_id)
157
+ return NotteEndpoint(
158
+ path=path,
159
+ response=TabSessionDebugResponse,
160
+ method="GET",
161
+ params=params,
162
+ )
163
+
164
+ @staticmethod
165
+ def session_debug_replay_endpoint(session_id: str | None = None) -> NotteEndpoint[BaseModel]:
166
+ """
167
+ Returns an endpoint for retrieving the replay for a session.
168
+ """
169
+ path = SessionsClient.SESSION_DEBUG_REPLAY
170
+ if session_id is not None:
171
+ path = path.format(session_id=session_id)
172
+ return NotteEndpoint(path=path, response=BaseModel, method="GET")
173
+
174
+ @staticmethod
175
+ def session_upload_cookies_endpoint() -> NotteEndpoint[UploadCookiesResponse]:
176
+ """
177
+ Returns a NotteEndpoint for uploading cookies to a session.
178
+ """
179
+ return NotteEndpoint(
180
+ path=SessionsClient.SESSION_UPLOAD_FILES_COOKIES, response=UploadCookiesResponse, method="POST"
181
+ )
182
+
183
+ @override
184
+ @staticmethod
185
+ def endpoints() -> Sequence[NotteEndpoint[BaseModel]]:
186
+ """Returns a sequence of available session endpoints.
187
+
188
+ Aggregates endpoints from SessionsClient for starting, closing, status checking, listing,
189
+ and debugging sessions (including tab-specific debugging)."""
190
+ return [
191
+ SessionsClient.session_start_endpoint(),
192
+ SessionsClient.session_stop_endpoint(),
193
+ SessionsClient.session_status_endpoint(),
194
+ SessionsClient.session_list_endpoint(),
195
+ SessionsClient.session_debug_endpoint(),
196
+ SessionsClient.session_debug_tab_endpoint(),
197
+ SessionsClient.session_debug_replay_endpoint(),
198
+ SessionsClient.session_upload_cookies_endpoint(),
199
+ ]
200
+
201
+ def start(self, **data: Unpack[SessionStartRequestDict]) -> SessionResponse:
202
+ """
203
+ Starts a new session using the provided keyword arguments.
204
+
205
+ Validates the input data against the session start model, sends a session start
206
+ request to the API, updates the last session response, and returns the response.
207
+
208
+ Args:
209
+ **data: Keyword arguments representing details for starting the session.
210
+
211
+ Returns:
212
+ SessionResponse: The response received from the session start endpoint.
213
+ """
214
+ request = SessionStartRequest.model_validate(data)
215
+ response = self.request(SessionsClient.session_start_endpoint().with_request(request))
216
+ return response
217
+
218
+ def stop(self, session_id: str) -> SessionResponse:
219
+ """
220
+ Stops an active session.
221
+
222
+ This method sends a request to the session stop endpoint using the specified
223
+ session ID or the currently active session. It validates the server response,
224
+ clears the internal session state, and returns the validated response.
225
+
226
+ Parameters:
227
+ session_id (str, optional): The identifier of the session to close. If not
228
+ provided, the active session ID is used. Raises ValueError if no active
229
+ session exists.
230
+
231
+ Returns:
232
+ SessionResponse: The validated response from the session stop request.
233
+ """
234
+ endpoint = SessionsClient.session_stop_endpoint(session_id=session_id)
235
+ response = self.request(endpoint)
236
+ return response
237
+
238
+ def status(self, session_id: str) -> SessionResponse:
239
+ """
240
+ Retrieves the current status of a session.
241
+
242
+ If no session_id is provided, the session ID from the last response is used. This method constructs
243
+ the status endpoint, validates the response against the SessionResponse model, updates the stored
244
+ session response, and returns the validated status.
245
+ """
246
+ endpoint = SessionsClient.session_status_endpoint(session_id=session_id)
247
+ response = self.request(endpoint)
248
+ return response
249
+
250
+ def list(self, **data: Unpack[ListRequestDict]) -> Sequence[SessionResponse]:
251
+ """
252
+ Retrieves a list of sessions from the API.
253
+
254
+ Validates keyword arguments as session listing criteria and requests the available
255
+ sessions. Returns a sequence of session response objects.
256
+ """
257
+ params = SessionListRequest.model_validate(data)
258
+ endpoint = SessionsClient.session_list_endpoint(params=params)
259
+ return self.request_list(endpoint)
260
+
261
+ def debug_info(self, session_id: str) -> SessionDebugResponse:
262
+ """
263
+ Retrieves debug information for a session.
264
+
265
+ If a session ID is provided, it is used; otherwise, the current session ID is retrieved.
266
+ Raises a ValueError if no valid session ID is available.
267
+
268
+ Args:
269
+ session_id (Optional[str]): An optional session identifier to use.
270
+
271
+ Returns:
272
+ SessionDebugResponse: The debug information response for the session.
273
+ """
274
+ endpoint = SessionsClient.session_debug_endpoint(session_id=session_id)
275
+ return self.request(endpoint)
276
+
277
+ def debug_tab_info(self, session_id: str, tab_idx: int | None = None) -> TabSessionDebugResponse:
278
+ """
279
+ Retrieves debug information for a specific tab in the current session.
280
+
281
+ If no session ID is provided, the active session is used. If a tab index is provided, the
282
+ debug request is scoped to that tab.
283
+
284
+ Parameters:
285
+ session_id (str, optional): The session identifier to use.
286
+ tab_idx (int, optional): The index of the tab for which to retrieve debug info.
287
+
288
+ Returns:
289
+ TabSessionDebugResponse: The response containing debug information for the specified tab.
290
+ """
291
+ params = TabSessionDebugRequest(tab_idx=tab_idx) if tab_idx is not None else None
292
+ endpoint = SessionsClient.session_debug_tab_endpoint(session_id=session_id, params=params)
293
+ return self.request(endpoint)
294
+
295
+ def replay(self, session_id: str) -> WebpReplay:
296
+ """
297
+ Downloads the replay for the specified session in webp format.
298
+
299
+ Args:
300
+ session_id: The identifier of the session to download the replay for.
301
+
302
+ Returns:
303
+ WebpReplay: The replay file in webp format.
304
+ """
305
+ endpoint = SessionsClient.session_debug_replay_endpoint(session_id=session_id)
306
+ file_bytes = self._request_file(endpoint, file_type="webp")
307
+ return WebpReplay(file_bytes)
308
+
309
+ def recording(self, session_id: str) -> SessionRecordingWebSocket:
310
+ """
311
+ Returns a SessionRecordingWebSocket for the specified session.
312
+ """
313
+ debug_info = self.debug_info(session_id=session_id)
314
+ return SessionRecordingWebSocket(wss_url=debug_info.ws.recording)
315
+
316
+ def upload_cookies(self, cookie_file: str | Path) -> UploadCookiesResponse:
317
+ """
318
+ Uploads cookies to the session.
319
+
320
+ Args:
321
+ cookie_file: The path to the cookie file (json format)
322
+ """
323
+ request = UploadCookiesRequest.from_json(cookie_file)
324
+ endpoint = SessionsClient.session_upload_cookies_endpoint()
325
+ return self.request(endpoint.with_request(request))
326
+
327
+ def viewer(self, session_id: str) -> None:
328
+ """
329
+ Opens a browser tab with the debug URL for visualizing the session.
330
+
331
+ Retrieves debug information for the specified session and opens
332
+ its debug URL in the default web browser.
333
+
334
+ Args:
335
+ session_id (str, optional): The session identifier to use.
336
+ If not provided, the current session ID is used.
337
+
338
+ Returns:
339
+ None
340
+ """
341
+ debug_info = self.debug_info(session_id=session_id)
342
+ # open browser tab with debug_url
343
+ _ = open_browser(debug_info.debug_url)
344
+
345
+
346
+ @final
347
+ class RemoteSessionFactory:
348
+ """
349
+ Factory for creating RemoteSession instances.
350
+
351
+ This factory provides a convenient way to create RemoteSession instances with
352
+ customizable configurations. It handles the validation of session creation requests
353
+ and sets up the appropriate connections.
354
+
355
+ Attributes:
356
+ client (SessionsClient): The client used to communicate with the Notte API.
357
+ """
358
+
359
+ class RemoteSession(SyncResource):
360
+ """
361
+ A remote session that can be managed through the Notte API.
362
+
363
+ This class provides an interface for starting, stopping, and monitoring sessions.
364
+ It implements the SyncResource interface for resource management and maintains
365
+ state about the current session execution.
366
+
367
+ Attributes:
368
+ request (SessionStartRequest): The configuration request used to create this session.
369
+ client (SessionsClient): The client used to communicate with the Notte API.
370
+ response (SessionResponse | None): The latest response from the session execution.
371
+ """
372
+
373
+ def __init__(self, client: SessionsClient, request: SessionStartRequest) -> None:
374
+ """
375
+ Initialize a new RemoteSession instance.
376
+
377
+ Args:
378
+ client (SessionsClient): The client used to communicate with the Notte API.
379
+ request (SessionStartRequest): The configuration request for this session.
380
+ """
381
+ self.request: SessionStartRequest = request
382
+ self.client: SessionsClient = client
383
+ self.response: SessionResponse | None = None
384
+
385
+ # #######################################################################
386
+ # ############################# Session #################################
387
+ # #######################################################################
388
+
389
+ @override
390
+ def start(self) -> None:
391
+ """
392
+ Start the session using the configured request.
393
+
394
+ This method sends a start request to the API and logs the session ID
395
+ and request details upon successful start.
396
+
397
+ Raises:
398
+ ValueError: If the session request is invalid.
399
+ """
400
+ self.response = self.client.start(**self.request.model_dump())
401
+ logger.info(
402
+ f"[Session] {self.session_id} started with request: {self.request.model_dump(exclude_none=True)}"
403
+ )
404
+
405
+ @override
406
+ def stop(self) -> None:
407
+ """
408
+ Stop the session and clean up resources.
409
+
410
+ This method sends a close request to the API and verifies that the session
411
+ was properly closed. It logs the session closure and raises an error if
412
+ the session fails to close.
413
+
414
+ Raises:
415
+ ValueError: If the session hasn't been started (no session_id available).
416
+ RuntimeError: If the session fails to close properly.
417
+ """
418
+ logger.info(f"[Session] {self.session_id} stopped")
419
+ self.response = self.client.stop(session_id=self.session_id)
420
+ if self.response.status != "closed":
421
+ raise RuntimeError(f"[Session] {self.session_id} failed to stop")
422
+
423
+ @property
424
+ def session_id(self) -> str:
425
+ """
426
+ Get the ID of the current session.
427
+
428
+ Returns:
429
+ str: The unique identifier of the current session.
430
+
431
+ Raises:
432
+ ValueError: If the session hasn't been started yet (no response available).
433
+ """
434
+ if self.response is None:
435
+ raise ValueError("You need to start the session first to get the session id")
436
+ return self.response.session_id
437
+
438
+ def replay(self) -> WebpReplay:
439
+ """
440
+ Get a replay of the session's execution in WEBP format.
441
+
442
+ Returns:
443
+ WebpReplay: The replay data in WEBP format.
444
+
445
+ Raises:
446
+ ValueError: If the session hasn't been started yet (no session_id available).
447
+ """
448
+ return self.client.replay(session_id=self.session_id)
449
+
450
+ def recording(self) -> SessionRecordingWebSocket:
451
+ """
452
+ Get a recording of the session's execution in WEBP format.
453
+ """
454
+ return self.client.recording(session_id=self.session_id)
455
+
456
+ def viewer(self) -> None:
457
+ """
458
+ Open a browser tab with the debug URL for visualizing the session.
459
+
460
+ This method opens the default web browser to display the session's debug interface.
461
+
462
+ Raises:
463
+ ValueError: If the session hasn't been started yet (no session_id available).
464
+ """
465
+ self.client.viewer(session_id=self.session_id)
466
+
467
+ def status(self) -> SessionResponse:
468
+ """
469
+ Get the current status of the session.
470
+
471
+ Returns:
472
+ SessionResponse: The current status information of the session.
473
+
474
+ Raises:
475
+ ValueError: If the session hasn't been started yet (no session_id available).
476
+ """
477
+ return self.client.status(session_id=self.session_id)
478
+
479
+ def debug_info(self) -> SessionDebugResponse:
480
+ """
481
+ Get detailed debug information for the session.
482
+
483
+ Returns:
484
+ SessionDebugResponse: Debug information for the session.
485
+
486
+ Raises:
487
+ ValueError: If the session hasn't been started yet (no session_id available).
488
+ """
489
+ return self.client.debug_info(session_id=self.session_id)
490
+
491
+ def cdp_url(self) -> str:
492
+ """
493
+ Get the Chrome DevTools Protocol WebSocket URL for the session.
494
+
495
+ This URL can be used to connect to the browser's debugging interface.
496
+
497
+ Returns:
498
+ str: The WebSocket URL for the Chrome DevTools Protocol.
499
+
500
+ Raises:
501
+ ValueError: If the session hasn't been started yet (no session_id available).
502
+ """
503
+ debug = self.debug_info()
504
+ return debug.ws.cdp
505
+
506
+ # #######################################################################
507
+ # ############################# PAGE ####################################
508
+ # #######################################################################
509
+
510
+ def scrape(self, **data: Unpack[ObserveRequestDict]) -> DataSpace:
511
+ return self.client.page.scrape(session_id=self.session_id, **data)
512
+
513
+ def observe(self, **data: Unpack[ObserveRequestDict]) -> Observation:
514
+ return self.client.page.observe(session_id=self.session_id, **data)
515
+
516
+ def step(self, **data: Unpack[StepRequestDict]) -> Observation:
517
+ return self.client.page.step(session_id=self.session_id, **data)
518
+
519
+ def __init__(self, client: SessionsClient) -> None:
520
+ """
521
+ Initialize a new RemoteSessionFactory instance.
522
+
523
+ Args:
524
+ client (SessionsClient): The client used to communicate with the Notte API.
525
+ """
526
+ self.client = client
527
+
528
+ def __call__(self, **data: Unpack[SessionStartRequestDict]) -> RemoteSession:
529
+ """
530
+ Create a new RemoteSession instance with the specified configuration.
531
+
532
+ This method validates the session creation request and returns a new
533
+ RemoteSession instance configured with the specified parameters.
534
+
535
+ Args:
536
+ **data: Keyword arguments for the session creation request.
537
+
538
+ Returns:
539
+ RemoteSession: A new RemoteSession instance configured with the specified parameters.
540
+ """
541
+ request = SessionStartRequest.model_validate(data)
542
+ return RemoteSessionFactory.RemoteSession(self.client, request)
@@ -0,0 +1,83 @@
1
+ from collections.abc import Sequence
2
+ from typing import Unpack
3
+
4
+ from loguru import logger
5
+ from pydantic import BaseModel
6
+ from typing_extensions import final, override
7
+
8
+ from notte_sdk.endpoints.base import BaseClient, NotteEndpoint
9
+ from notte_sdk.endpoints.personas import PersonasClient
10
+ from notte_sdk.types import (
11
+ PersonaCreateRequest,
12
+ PersonaCreateRequestDict,
13
+ PersonaCreateResponse,
14
+ )
15
+ from notte_sdk.vault import NotteVault
16
+
17
+
18
+ @final
19
+ class VaultsClient(BaseClient):
20
+ """
21
+ Client for the Notte API.
22
+
23
+ Note: this client is only able to handle one session at a time.
24
+ If you need to handle multiple sessions, you need to create a new client for each session.
25
+ """
26
+
27
+ # Session
28
+ CREATE_VAULT = "create"
29
+
30
+ def __init__(
31
+ self,
32
+ persona_client: PersonasClient,
33
+ api_key: str | None = None,
34
+ verbose: bool = False,
35
+ ):
36
+ """
37
+ Initialize a VaultsClient instance.
38
+
39
+ Initializes the client with an optional API key for vault management.
40
+ """
41
+ super().__init__(base_endpoint_path="vaults", api_key=api_key, verbose=verbose)
42
+ self.persona_client = persona_client
43
+
44
+ def get(self, vault_id: str) -> NotteVault:
45
+ return NotteVault(persona_client=self.persona_client, persona_id=vault_id)
46
+
47
+ @override
48
+ @staticmethod
49
+ def endpoints() -> Sequence[NotteEndpoint[BaseModel]]:
50
+ """Returns the available vault endpoints.
51
+
52
+ Aggregates endpoints from PersonasClient for creating personas, reading messages, etc..."""
53
+ return [
54
+ VaultsClient.create_vault_endpoint(),
55
+ ]
56
+
57
+ @staticmethod
58
+ def create_vault_endpoint() -> NotteEndpoint[PersonaCreateResponse]:
59
+ """
60
+ Returns a NotteEndpoint configured for creating a persona.
61
+
62
+ The returned endpoint uses the credentials from PersonasClient with the POST method and expects a PersonaCreateResponse.
63
+ """
64
+ return NotteEndpoint(
65
+ path=VaultsClient.CREATE_VAULT,
66
+ response=PersonaCreateResponse,
67
+ method="POST",
68
+ )
69
+
70
+ def create(self, **data: Unpack[PersonaCreateRequestDict]) -> NotteVault:
71
+ """
72
+ Create vault
73
+
74
+ Args:
75
+
76
+ Returns:
77
+ PersonaCreateResponse: The persona created
78
+ """
79
+ params = PersonaCreateRequest.model_validate(data)
80
+ response = self.request(VaultsClient.create_vault_endpoint().with_request(params))
81
+ logger.info(f"Created vault with id: {response.persona_id}. Don't lose this id!")
82
+
83
+ return NotteVault(self.persona_client, persona_id=response.persona_id)
notte_sdk/errors.py ADDED
@@ -0,0 +1,40 @@
1
+ from notte_core.errors.base import NotteBaseError
2
+ from requests import Response
3
+
4
+
5
+ class NotteAPIError(NotteBaseError):
6
+ def __init__(self, path: str, response: Response) -> None:
7
+ try:
8
+ error = response.json()
9
+ except Exception:
10
+ error = response.text
11
+
12
+ super().__init__(
13
+ dev_message=f"Request to `{path}` failed with status code {response.status_code}: {error}",
14
+ user_message="An unexpected error occurred during the request to the Notte API.",
15
+ should_notify_team=True,
16
+ # agent message not relevant here
17
+ agent_message=None,
18
+ )
19
+
20
+
21
+ class AuthenticationError(NotteBaseError):
22
+ def __init__(self, message: str) -> None:
23
+ super().__init__(
24
+ dev_message=f"Authentication failed. {message}",
25
+ user_message="Authentication failed. Please check your credentials or upgrade your plan.",
26
+ should_retry_later=False,
27
+ # agent message not relevant here
28
+ agent_message=None,
29
+ )
30
+
31
+
32
+ class InvalidRequestError(NotteBaseError):
33
+ def __init__(self, message: str) -> None:
34
+ super().__init__(
35
+ dev_message=f"Invalid request. {message}",
36
+ user_message="Invalid request. Please check your request parameters.",
37
+ should_retry_later=False,
38
+ # agent message not relevant here
39
+ agent_message=None,
40
+ )
notte_sdk/py.typed ADDED
File without changes