narada 0.1.31__py3-none-any.whl → 0.1.33a1__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.
narada/__init__.py
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
from narada.client import Narada
|
|
2
|
+
from narada.config import BrowserConfig, ProxyConfig
|
|
3
|
+
from narada.utils import download_file, render_html
|
|
4
|
+
from narada.version import __version__
|
|
5
|
+
from narada.window import CloudBrowserWindow, LocalBrowserWindow, RemoteBrowserWindow
|
|
1
6
|
from narada_core.errors import (
|
|
2
7
|
NaradaError,
|
|
3
8
|
NaradaExtensionMissingError,
|
|
@@ -8,16 +13,11 @@ from narada_core.errors import (
|
|
|
8
13
|
)
|
|
9
14
|
from narada_core.models import Agent, File, Response, ResponseContent
|
|
10
15
|
|
|
11
|
-
from narada.client import Narada
|
|
12
|
-
from narada.config import BrowserConfig, ProxyConfig
|
|
13
|
-
from narada.utils import download_file, render_html
|
|
14
|
-
from narada.version import __version__
|
|
15
|
-
from narada.window import LocalBrowserWindow, RemoteBrowserWindow
|
|
16
|
-
|
|
17
16
|
__all__ = [
|
|
18
17
|
"__version__",
|
|
19
18
|
"Agent",
|
|
20
19
|
"BrowserConfig",
|
|
20
|
+
"CloudBrowserWindow",
|
|
21
21
|
"download_file",
|
|
22
22
|
"File",
|
|
23
23
|
"LocalBrowserWindow",
|
narada/client.py
CHANGED
|
@@ -11,6 +11,14 @@ from uuid import uuid4
|
|
|
11
11
|
|
|
12
12
|
import aiohttp
|
|
13
13
|
import semver
|
|
14
|
+
from narada.config import BrowserConfig, ProxyConfig
|
|
15
|
+
from narada.utils import assert_never
|
|
16
|
+
from narada.version import __version__
|
|
17
|
+
from narada.window import (
|
|
18
|
+
LocalBrowserWindow,
|
|
19
|
+
CloudBrowserWindow,
|
|
20
|
+
create_side_panel_url,
|
|
21
|
+
)
|
|
14
22
|
from narada_core.errors import (
|
|
15
23
|
NaradaExtensionMissingError,
|
|
16
24
|
NaradaExtensionUnauthenticatedError,
|
|
@@ -26,19 +34,14 @@ from playwright.async_api import (
|
|
|
26
34
|
ElementHandle,
|
|
27
35
|
Page,
|
|
28
36
|
Playwright,
|
|
29
|
-
async_playwright,
|
|
30
37
|
)
|
|
38
|
+
from playwright.async_api import TimeoutError as PlaywrightTimeoutError
|
|
31
39
|
from playwright.async_api import (
|
|
32
|
-
|
|
40
|
+
async_playwright,
|
|
33
41
|
)
|
|
34
42
|
from playwright.async_api._context_manager import PlaywrightContextManager
|
|
35
43
|
from rich.console import Console
|
|
36
44
|
|
|
37
|
-
from narada.config import BrowserConfig, ProxyConfig
|
|
38
|
-
from narada.utils import assert_never
|
|
39
|
-
from narada.version import __version__
|
|
40
|
-
from narada.window import LocalBrowserWindow, create_side_panel_url
|
|
41
|
-
|
|
42
45
|
|
|
43
46
|
@dataclass
|
|
44
47
|
class _LaunchBrowserResult:
|
|
@@ -58,10 +61,12 @@ class Narada:
|
|
|
58
61
|
_console: Console
|
|
59
62
|
_playwright_context_manager: PlaywrightContextManager | None = None
|
|
60
63
|
_playwright: Playwright | None = None
|
|
64
|
+
_cloud_windows: set[CloudBrowserWindow]
|
|
61
65
|
|
|
62
66
|
def __init__(self, *, api_key: str | None = None) -> None:
|
|
63
67
|
self._api_key = api_key or os.environ["NARADA_API_KEY"]
|
|
64
68
|
self._console = Console()
|
|
69
|
+
self._cloud_windows = set()
|
|
65
70
|
|
|
66
71
|
async def __aenter__(self) -> Narada:
|
|
67
72
|
await self._validate_sdk_config()
|
|
@@ -71,6 +76,11 @@ class Narada:
|
|
|
71
76
|
return self
|
|
72
77
|
|
|
73
78
|
async def __aexit__(self, *args: Any) -> None:
|
|
79
|
+
async with asyncio.TaskGroup() as tg:
|
|
80
|
+
for cloud_window in self._cloud_windows:
|
|
81
|
+
tg.create_task(cloud_window.cleanup())
|
|
82
|
+
self._cloud_windows.clear()
|
|
83
|
+
|
|
74
84
|
if self._playwright_context_manager is None:
|
|
75
85
|
return
|
|
76
86
|
|
|
@@ -134,6 +144,121 @@ class Narada:
|
|
|
134
144
|
context=side_panel_page.context,
|
|
135
145
|
)
|
|
136
146
|
|
|
147
|
+
async def open_and_initialize_cloud_browser_window(
|
|
148
|
+
self,
|
|
149
|
+
config: BrowserConfig | None = None,
|
|
150
|
+
session_name: str | None = None,
|
|
151
|
+
session_timeout: int | None = None,
|
|
152
|
+
) -> CloudBrowserWindow:
|
|
153
|
+
"""Creates a cloud browser by calling the backend.
|
|
154
|
+
|
|
155
|
+
The backend creates a cloud browser session and returns
|
|
156
|
+
a CDP WebSocket URL. This method connects to it, initializes the extension,
|
|
157
|
+
and returns a CloudBrowserWindow instance.
|
|
158
|
+
"""
|
|
159
|
+
assert self._playwright is not None
|
|
160
|
+
playwright = self._playwright
|
|
161
|
+
|
|
162
|
+
config = config or BrowserConfig()
|
|
163
|
+
base_url = os.getenv("NARADA_API_BASE_URL", "https://api.narada.ai/fast/v2")
|
|
164
|
+
request_body = {
|
|
165
|
+
"session_name": session_name,
|
|
166
|
+
"session_timeout": session_timeout,
|
|
167
|
+
}
|
|
168
|
+
endpoint_url = f"{base_url}/cloud-browser/create-cloud-browser-session"
|
|
169
|
+
|
|
170
|
+
async with aiohttp.ClientSession() as session:
|
|
171
|
+
async with session.post(
|
|
172
|
+
endpoint_url,
|
|
173
|
+
headers={"x-api-key": self._api_key},
|
|
174
|
+
json=request_body,
|
|
175
|
+
timeout=aiohttp.ClientTimeout(
|
|
176
|
+
total=180
|
|
177
|
+
), # 3 minutes for session startup
|
|
178
|
+
) as resp:
|
|
179
|
+
if not resp.ok:
|
|
180
|
+
error_text = await resp.text()
|
|
181
|
+
raise RuntimeError(
|
|
182
|
+
f"Failed to create cloud browser session: {resp.status} {error_text}\n"
|
|
183
|
+
f"Endpoint URL: {endpoint_url}"
|
|
184
|
+
)
|
|
185
|
+
response_data = await resp.json()
|
|
186
|
+
|
|
187
|
+
cdp_websocket_url = response_data["cdp_websocket_url"]
|
|
188
|
+
session_id = response_data["session_id"]
|
|
189
|
+
login_url = response_data["login_url"]
|
|
190
|
+
cdp_auth_headers = response_data.get("cdp_auth_headers")
|
|
191
|
+
|
|
192
|
+
# Connect to browser via CDP with authentication headers
|
|
193
|
+
try:
|
|
194
|
+
browser = await playwright.chromium.connect_over_cdp(
|
|
195
|
+
cdp_websocket_url, headers=cdp_auth_headers
|
|
196
|
+
)
|
|
197
|
+
except Exception:
|
|
198
|
+
# Clean up the session if CDP connection fails
|
|
199
|
+
try:
|
|
200
|
+
async with aiohttp.ClientSession() as cleanup_session:
|
|
201
|
+
async with cleanup_session.post(
|
|
202
|
+
f"{base_url}/cloud-browser/stop-cloud-browser-session",
|
|
203
|
+
headers={"x-api-key": self._api_key},
|
|
204
|
+
json={"session_id": session_id},
|
|
205
|
+
timeout=aiohttp.ClientTimeout(total=10),
|
|
206
|
+
) as resp:
|
|
207
|
+
if resp.ok:
|
|
208
|
+
logging.info(
|
|
209
|
+
f"Cleaned up session {session_id} after CDP connection failure"
|
|
210
|
+
)
|
|
211
|
+
else:
|
|
212
|
+
logging.warning(
|
|
213
|
+
f"Failed to cleanup session {session_id}: {resp.status}"
|
|
214
|
+
)
|
|
215
|
+
except Exception as cleanup_error:
|
|
216
|
+
logging.warning(
|
|
217
|
+
f"Error cleaning up session {session_id}: {cleanup_error}"
|
|
218
|
+
)
|
|
219
|
+
# Re-raise the original connection error
|
|
220
|
+
raise
|
|
221
|
+
context = (
|
|
222
|
+
browser.contexts[0] if browser.contexts else await browser.new_context()
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# Navigate to login URL (provided by backend with custom token)
|
|
226
|
+
initialization_page = await context.new_page()
|
|
227
|
+
await initialization_page.goto(
|
|
228
|
+
login_url, wait_until="domcontentloaded", timeout=60_000
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Wait for sign-in to process to complete.
|
|
232
|
+
await asyncio.sleep(15) # TODO: improve it in the future
|
|
233
|
+
await initialization_page.reload(wait_until="domcontentloaded", timeout=60_000)
|
|
234
|
+
|
|
235
|
+
# Wait for browser window ID
|
|
236
|
+
browser_window_id = await self._wait_for_browser_window_id(
|
|
237
|
+
initialization_page, config
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# TODO: consider this
|
|
241
|
+
# Get side panel page
|
|
242
|
+
# side_panel_url = create_side_panel_url(config, browser_window_id)
|
|
243
|
+
# side_panel_page = next(
|
|
244
|
+
# (p for p in context.pages if p.url == side_panel_url), None
|
|
245
|
+
# )
|
|
246
|
+
# await self._fix_download_behavior(side_panel_page)
|
|
247
|
+
|
|
248
|
+
cloud_window = CloudBrowserWindow(
|
|
249
|
+
browser_window_id=browser_window_id,
|
|
250
|
+
session_id=session_id,
|
|
251
|
+
api_key=self._api_key,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Track the window for cleanup in __aexit__
|
|
255
|
+
self._cloud_windows.add(cloud_window)
|
|
256
|
+
|
|
257
|
+
if config.interactive:
|
|
258
|
+
self._print_success_message(browser_window_id)
|
|
259
|
+
|
|
260
|
+
return cloud_window
|
|
261
|
+
|
|
137
262
|
async def initialize_in_existing_browser_window(
|
|
138
263
|
self, config: BrowserConfig | None = None
|
|
139
264
|
) -> LocalBrowserWindow:
|
narada/window.py
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import logging
|
|
2
3
|
import os
|
|
3
4
|
import time
|
|
4
5
|
from abc import ABC
|
|
5
6
|
from http import HTTPStatus
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import IO, Any,
|
|
8
|
+
from typing import IO, Any, TypeVar, overload
|
|
8
9
|
|
|
9
10
|
import aiohttp
|
|
11
|
+
from narada.config import BrowserConfig
|
|
10
12
|
from narada_core.actions.models import (
|
|
11
|
-
|
|
13
|
+
AgenticMouseAction,
|
|
14
|
+
AgenticMouseActionRequest,
|
|
12
15
|
AgenticSelectorAction,
|
|
13
16
|
AgenticSelectorRequest,
|
|
14
17
|
AgenticSelectorResponse,
|
|
15
|
-
AgenticMouseActionRequest,
|
|
16
|
-
AgenticMouseAction,
|
|
17
18
|
AgenticSelectors,
|
|
18
19
|
AgentResponse,
|
|
19
20
|
AgentUsage,
|
|
20
21
|
CloseWindowRequest,
|
|
21
22
|
ExtensionActionRequest,
|
|
22
23
|
ExtensionActionResponse,
|
|
24
|
+
GetFullHtmlRequest,
|
|
25
|
+
GetFullHtmlResponse,
|
|
26
|
+
GetScreenshotRequest,
|
|
27
|
+
GetScreenshotResponse,
|
|
28
|
+
GetSimplifiedHtmlRequest,
|
|
29
|
+
GetSimplifiedHtmlResponse,
|
|
23
30
|
GoToUrlRequest,
|
|
24
31
|
PrintMessageRequest,
|
|
25
32
|
ReadGoogleSheetRequest,
|
|
26
33
|
ReadGoogleSheetResponse,
|
|
27
|
-
WriteGoogleSheetRequest,
|
|
28
34
|
RecordedClick,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
GetSimplifiedHtmlRequest,
|
|
32
|
-
GetSimplifiedHtmlResponse,
|
|
33
|
-
GetScreenshotRequest,
|
|
34
|
-
GetScreenshotResponse,
|
|
35
|
+
WriteGoogleSheetRequest,
|
|
36
|
+
parse_action_trace,
|
|
35
37
|
)
|
|
36
38
|
from narada_core.errors import (
|
|
37
39
|
NaradaAgentTimeoutError_INTERNAL_DO_NOT_USE,
|
|
@@ -41,14 +43,17 @@ from narada_core.errors import (
|
|
|
41
43
|
from narada_core.models import (
|
|
42
44
|
Agent,
|
|
43
45
|
File,
|
|
46
|
+
McpServer,
|
|
44
47
|
RemoteDispatchChatHistoryItem,
|
|
45
48
|
Response,
|
|
46
49
|
UserResourceCredentials,
|
|
47
50
|
)
|
|
48
|
-
from playwright.async_api import
|
|
51
|
+
from playwright.async_api import (
|
|
52
|
+
BrowserContext,
|
|
53
|
+
)
|
|
49
54
|
from pydantic import BaseModel
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
logger = logging.getLogger(__name__)
|
|
52
57
|
|
|
53
58
|
_StructuredOutput = TypeVar("_StructuredOutput", bound=BaseModel)
|
|
54
59
|
|
|
@@ -129,6 +134,7 @@ class BaseBrowserWindow(ABC):
|
|
|
129
134
|
attachment: File | None = None,
|
|
130
135
|
time_zone: str = "America/Los_Angeles",
|
|
131
136
|
user_resource_credentials: UserResourceCredentials | None = None,
|
|
137
|
+
mcp_servers: list[McpServer] | None = None,
|
|
132
138
|
variables: dict[str, str] | None = None,
|
|
133
139
|
callback_url: str | None = None,
|
|
134
140
|
callback_secret: str | None = None,
|
|
@@ -151,6 +157,7 @@ class BaseBrowserWindow(ABC):
|
|
|
151
157
|
attachment: File | None = None,
|
|
152
158
|
time_zone: str = "America/Los_Angeles",
|
|
153
159
|
user_resource_credentials: UserResourceCredentials | None = None,
|
|
160
|
+
mcp_servers: list[McpServer] | None = None,
|
|
154
161
|
variables: dict[str, str] | None = None,
|
|
155
162
|
callback_url: str | None = None,
|
|
156
163
|
callback_secret: str | None = None,
|
|
@@ -172,6 +179,7 @@ class BaseBrowserWindow(ABC):
|
|
|
172
179
|
attachment: File | None = None,
|
|
173
180
|
time_zone: str = "America/Los_Angeles",
|
|
174
181
|
user_resource_credentials: UserResourceCredentials | None = None,
|
|
182
|
+
mcp_servers: list[McpServer] | None = None,
|
|
175
183
|
variables: dict[str, str] | None = None,
|
|
176
184
|
callback_url: str | None = None,
|
|
177
185
|
callback_secret: str | None = None,
|
|
@@ -213,6 +221,10 @@ class BaseBrowserWindow(ABC):
|
|
|
213
221
|
body["attachment"] = attachment
|
|
214
222
|
if user_resource_credentials is not None:
|
|
215
223
|
body["userResourceCredentials"] = user_resource_credentials
|
|
224
|
+
if mcp_servers is not None:
|
|
225
|
+
body["mcpServers"] = [
|
|
226
|
+
server.model_dump(mode="json") for server in mcp_servers
|
|
227
|
+
]
|
|
216
228
|
if variables is not None:
|
|
217
229
|
body["variables"] = variables
|
|
218
230
|
if callback_url is not None:
|
|
@@ -278,6 +290,7 @@ class BaseBrowserWindow(ABC):
|
|
|
278
290
|
output_schema: None = None,
|
|
279
291
|
attachment: File | None = None,
|
|
280
292
|
time_zone: str = "America/Los_Angeles",
|
|
293
|
+
mcp_servers: list[McpServer] | None = None,
|
|
281
294
|
variables: dict[str, str] | None = None,
|
|
282
295
|
timeout: int = 1000,
|
|
283
296
|
) -> AgentResponse[None]: ...
|
|
@@ -293,6 +306,7 @@ class BaseBrowserWindow(ABC):
|
|
|
293
306
|
output_schema: type[_StructuredOutput],
|
|
294
307
|
attachment: File | None = None,
|
|
295
308
|
time_zone: str = "America/Los_Angeles",
|
|
309
|
+
mcp_servers: list[McpServer] | None = None,
|
|
296
310
|
variables: dict[str, str] | None = None,
|
|
297
311
|
timeout: int = 1000,
|
|
298
312
|
) -> AgentResponse[_StructuredOutput]: ...
|
|
@@ -307,6 +321,7 @@ class BaseBrowserWindow(ABC):
|
|
|
307
321
|
output_schema: type[BaseModel] | None = None,
|
|
308
322
|
attachment: File | None = None,
|
|
309
323
|
time_zone: str = "America/Los_Angeles",
|
|
324
|
+
mcp_servers: list[McpServer] | None = None,
|
|
310
325
|
variables: dict[str, str] | None = None,
|
|
311
326
|
timeout: int = 1000,
|
|
312
327
|
) -> AgentResponse:
|
|
@@ -319,6 +334,7 @@ class BaseBrowserWindow(ABC):
|
|
|
319
334
|
output_schema=output_schema,
|
|
320
335
|
attachment=attachment,
|
|
321
336
|
time_zone=time_zone,
|
|
337
|
+
mcp_servers=mcp_servers,
|
|
322
338
|
variables=variables,
|
|
323
339
|
timeout=timeout,
|
|
324
340
|
)
|
|
@@ -327,7 +343,7 @@ class BaseBrowserWindow(ABC):
|
|
|
327
343
|
|
|
328
344
|
action_trace_raw = response_content.get("actionTrace")
|
|
329
345
|
action_trace = (
|
|
330
|
-
|
|
346
|
+
parse_action_trace(action_trace_raw)
|
|
331
347
|
if action_trace_raw is not None
|
|
332
348
|
else None
|
|
333
349
|
)
|
|
@@ -362,14 +378,13 @@ class BaseBrowserWindow(ABC):
|
|
|
362
378
|
AgenticSelectorRequest(
|
|
363
379
|
action=action,
|
|
364
380
|
selectors=selectors,
|
|
365
|
-
response_model=response_model,
|
|
366
381
|
fallback_operator_query=fallback_operator_query,
|
|
367
382
|
),
|
|
368
383
|
timeout=timeout,
|
|
369
384
|
)
|
|
370
385
|
|
|
371
386
|
if result is None:
|
|
372
|
-
return
|
|
387
|
+
return AgenticSelectorResponse(value=None)
|
|
373
388
|
|
|
374
389
|
return result
|
|
375
390
|
|
|
@@ -542,9 +557,10 @@ class LocalBrowserWindow(BaseBrowserWindow):
|
|
|
542
557
|
config: BrowserConfig,
|
|
543
558
|
context: BrowserContext,
|
|
544
559
|
) -> None:
|
|
560
|
+
base_url = os.getenv("NARADA_API_BASE_URL", "https://api.narada.ai/fast/v2")
|
|
545
561
|
super().__init__(
|
|
546
562
|
api_key=api_key,
|
|
547
|
-
base_url=
|
|
563
|
+
base_url=base_url,
|
|
548
564
|
browser_window_id=browser_window_id,
|
|
549
565
|
)
|
|
550
566
|
self._browser_process_id = browser_process_id
|
|
@@ -576,9 +592,10 @@ class LocalBrowserWindow(BaseBrowserWindow):
|
|
|
576
592
|
|
|
577
593
|
class RemoteBrowserWindow(BaseBrowserWindow):
|
|
578
594
|
def __init__(self, *, browser_window_id: str, api_key: str | None = None) -> None:
|
|
595
|
+
base_url = os.getenv("NARADA_API_BASE_URL", "https://api.narada.ai/fast/v2")
|
|
579
596
|
super().__init__(
|
|
580
597
|
api_key=api_key or os.environ["NARADA_API_KEY"],
|
|
581
|
-
base_url=
|
|
598
|
+
base_url=base_url,
|
|
582
599
|
browser_window_id=browser_window_id,
|
|
583
600
|
)
|
|
584
601
|
|
|
@@ -586,5 +603,51 @@ class RemoteBrowserWindow(BaseBrowserWindow):
|
|
|
586
603
|
return f"RemoteBrowserWindow(browser_window_id={self.browser_window_id})"
|
|
587
604
|
|
|
588
605
|
|
|
606
|
+
class CloudBrowserWindow(BaseBrowserWindow):
|
|
607
|
+
"""A browser window that connects to a backend-cloud browser session via CDP.
|
|
608
|
+
|
|
609
|
+
This class connects to a cloud browser session created by the backend API and provides
|
|
610
|
+
the same interface as other browser window classes for agent operations.
|
|
611
|
+
"""
|
|
612
|
+
|
|
613
|
+
def __init__(
|
|
614
|
+
self,
|
|
615
|
+
*,
|
|
616
|
+
browser_window_id: str,
|
|
617
|
+
session_id: str,
|
|
618
|
+
api_key: str | None = None,
|
|
619
|
+
) -> None:
|
|
620
|
+
base_url = os.getenv("NARADA_API_BASE_URL", "https://api.narada.ai/fast/v2")
|
|
621
|
+
super().__init__(
|
|
622
|
+
api_key=api_key or os.environ["NARADA_API_KEY"],
|
|
623
|
+
base_url=base_url,
|
|
624
|
+
browser_window_id=browser_window_id,
|
|
625
|
+
)
|
|
626
|
+
self._session_id = session_id
|
|
627
|
+
|
|
628
|
+
async def cleanup(self) -> None:
|
|
629
|
+
"""Stop the cloud browser session."""
|
|
630
|
+
try:
|
|
631
|
+
async with aiohttp.ClientSession() as session:
|
|
632
|
+
async with session.post(
|
|
633
|
+
f"{self._base_url}/cloud-browser/stop-cloud-browser-session",
|
|
634
|
+
headers={"x-api-key": self._api_key},
|
|
635
|
+
json={
|
|
636
|
+
"session_id": self._session_id,
|
|
637
|
+
},
|
|
638
|
+
timeout=aiohttp.ClientTimeout(total=10),
|
|
639
|
+
) as resp:
|
|
640
|
+
if resp.ok:
|
|
641
|
+
response_data = await resp.json()
|
|
642
|
+
if not response_data.get("success"):
|
|
643
|
+
logger.warning(
|
|
644
|
+
f"Failed to stop session: {response_data.get('message')}"
|
|
645
|
+
)
|
|
646
|
+
else:
|
|
647
|
+
logger.warning(f"Failed to stop session: {resp.status}")
|
|
648
|
+
except Exception as e:
|
|
649
|
+
logger.warning(f"Error calling stop session endpoint: {e}")
|
|
650
|
+
|
|
651
|
+
|
|
589
652
|
def create_side_panel_url(config: BrowserConfig, browser_window_id: str) -> str:
|
|
590
653
|
return f"chrome-extension://{config.extension_id}/sidepanel.html?browserWindowId={browser_window_id}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: narada
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.33a1
|
|
4
4
|
Summary: Python client SDK for Narada
|
|
5
5
|
Project-URL: Homepage, https://github.com/NaradaAI/narada-python-sdk/narada
|
|
6
6
|
Project-URL: Repository, https://github.com/NaradaAI/narada-python-sdk
|
|
@@ -9,7 +9,7 @@ Author-email: Narada <support@narada.ai>
|
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
Requires-Dist: aiohttp>=3.12.13
|
|
12
|
-
Requires-Dist: narada-core==0.0.
|
|
12
|
+
Requires-Dist: narada-core==0.0.10
|
|
13
13
|
Requires-Dist: playwright>=1.53.0
|
|
14
14
|
Requires-Dist: rich>=14.0.0
|
|
15
15
|
Requires-Dist: semver>=3.0.4
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
narada/__init__.py,sha256=gVa9HUFTeHot7VR2XPtCEsVeRiK7MDJJvKU1eEhLqXQ,1013
|
|
2
|
+
narada/client.py,sha256=Ea-zyJo6rZCQNi1higShelILkR9FLpNrtYoFse7heUA,26630
|
|
3
|
+
narada/config.py,sha256=S0B8GNd-0td_69oKaPN60WAq_ODeYU7avE_KAxN5vCg,3052
|
|
4
|
+
narada/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
narada/utils.py,sha256=gdLwNMXPpRohDcIIe0cB3KhvZ8X1QfAlKVh1sXWeJmk,1284
|
|
6
|
+
narada/version.py,sha256=kwW6yy0_4Pf3kt888eeCG0VwBb2L2rCkrkpdZEC_3rA,193
|
|
7
|
+
narada/window.py,sha256=e3pXn-wQMKm8QRvtAKfep0iGQE2LP9doP85z1t6VVpI,23036
|
|
8
|
+
narada-0.1.33a1.dist-info/METADATA,sha256=e3h7vEqdOHWEedcZw83trCPHVUPUry3FiE8gWu1aifM,5149
|
|
9
|
+
narada-0.1.33a1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
10
|
+
narada-0.1.33a1.dist-info/RECORD,,
|
narada-0.1.31.dist-info/RECORD
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
narada/__init__.py,sha256=2AnpZVQpkh4-onnvbgHX1Wlq1Fa8ya4vAzy2fbS0bCY,968
|
|
2
|
-
narada/client.py,sha256=_nTRHkiYt7lmUgO0HibVagrPXf523LCbWx8JmuVGgoo,21622
|
|
3
|
-
narada/config.py,sha256=S0B8GNd-0td_69oKaPN60WAq_ODeYU7avE_KAxN5vCg,3052
|
|
4
|
-
narada/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
narada/utils.py,sha256=gdLwNMXPpRohDcIIe0cB3KhvZ8X1QfAlKVh1sXWeJmk,1284
|
|
6
|
-
narada/version.py,sha256=kwW6yy0_4Pf3kt888eeCG0VwBb2L2rCkrkpdZEC_3rA,193
|
|
7
|
-
narada/window.py,sha256=_RyS_oIHJrFJ5ksEvde7NNiGfklVm9uSQoKFFEbUcYw,20648
|
|
8
|
-
narada-0.1.31.dist-info/METADATA,sha256=QJT-6CEwxUA5FMbkBlP9JtzfWtCBJWZD8VQvY3d_xeU,5146
|
|
9
|
-
narada-0.1.31.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
10
|
-
narada-0.1.31.dist-info/RECORD,,
|
|
File without changes
|