Skip to content

Commit e014d5e

Browse files
Den 229 new ergonomics (#47)
* Added functions to basebrowser that control active page for nicer ergonomics. Also added a global browser and a fill fields function. * added timeout to ask and improved goto and fill_fields. Removed global browser. * Added authentication_on parameter when initiating the browser. * Renamed LLMConfig to APIConfig to contain a Dendrite API key. It is now possible to use only a Dendrite API key when using the SDK. The option to use own API keys is still available for now. * add script that generates almost working sync code * update sync sdk name in script * remove and fix all type:ignore * update sdk with async and sync * add poe task runner for simplifying sync generation * add first test for sync * fixed small typo * added .mp3 to gitignore so that the download tests result isn't accidentally pushed * made auth param less verbose * Renamed to less verbose names. Added imports to top level in dendrite_sdk. Modified generate_sync to account for changed names. Added get element with dict to server with same branch name. * Renamed to even less verbose names. * Updated incorrect docs string * Changes to dendrite page protocol, added more helpful mixins. * rename playwright page * move tests out of module * remove unused dependencies * update test to save download to temp * remove unused .gitignore for mp3 --------- Co-authored-by: Arian Hanifi <[email protected]>
1 parent f2481eb commit e014d5e

File tree

151 files changed

+4873
-833
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

151 files changed

+4873
-833
lines changed

.env.example

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ DENDRITE_API_KEY=
22
OPENAI_API_KEY=
33
ANTHROPIC_API_KEY=
44

5-
# If using BrowserBaseBrowser
5+
# If using Browserbase
66
BROWSERBASE_API_KEY=
77
BROWSERBASE_PROJECT_ID=

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ test_screenshots/*
88
.vscode/
99
dist/
1010
examples/
11+
tmp/

README.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
With Dendrite, you can code a **email sending tool** like this:
1717

1818
```python
19-
from dendrite import DendriteBrowser
19+
from dendrite import AsyncDendrite
2020

2121
# Provide this tool to an agent by using e.g crewAI, llamaIndex, langchain or your own framework
2222
async def send_email(to: str, subject: str, body: str):
23-
async with DendriteBrowser() as dendrite:
23+
async with AsyncDendrite() as dendrite:
2424

2525
# Your agent will be able to access your outlook account now. You can mirror your browser's auth sessions to your agent with our Chrome Extension "Dendrite Vault".
2626
await dendrite.authenticate("outlook.live.com")
@@ -44,7 +44,7 @@ Sending emails is cool, but if that's all our agent can do it kind of sucks. So,
4444

4545
```python
4646
async def get_and_analyze_transactions(prompt: str) -> str:
47-
async with DendriteBrowser() as dendrite:
47+
async with AsyncDendrite() as dendrite:
4848
await dendrite.authenticate("mercury.com")
4949
page = await dendrite.goto("https://app.mercury.com/transactions", expected_outcome="We should arrive at the dashboard") # Raise an exception if we aren't logged in.
5050
await page.wait_for("The transactions page to have loaded")
@@ -64,7 +64,7 @@ Finally, it would be cool if we could add the amount of monthly visitors from Go
6464

6565
```python
6666
async def get_visitor_stats() -> int:
67-
async with DendriteBrowser() as dendrite:
67+
async with AsyncDendrite() as dendrite:
6868
await dendrite.authenticate("analytics.google.com")
6969
page = await dendrite.goto("https://analytics.google.com/analytics/web")
7070
await page.wait_for("The analytics page to have loaded")
@@ -111,11 +111,11 @@ poetry add dendrite-sdk && poetry run playwright install
111111

112112
## Hello World Example
113113

114-
For our first Dendrite script, let's start the `DendriteBrowser`, go to google.com and enter "hello world" into the search field:
114+
For our first Dendrite script, let's start the `AsyncDendrite`, go to google.com and enter "hello world" into the search field:
115115

116116
```python main.py
117117
import asyncio
118-
from dendrite_sdk import DendriteBrowser
118+
from dendrite_sdk import AsyncDendrite
119119

120120

121121
async def hello_world():
@@ -127,13 +127,13 @@ async def hello_world():
127127
dendrite_api_key = "..."
128128

129129
# Initate the Dendrite Browser
130-
browser = DendriteBrowser(
130+
browser = AsyncDendrite(
131131
openai_api_key=openai_api_key,
132132
anthropic_api_key=anthropic_api_key,
133133
dendrite_api_key=dendrite_api_key,
134134
)
135135

136-
# Navigate with `goto`, which returns a 'DendritePage' that controls the current page.
136+
# Navigate with `goto`, which returns a 'AsyncPage' that controls the current page.
137137
page = await browser.goto("https://google.com")
138138

139139
# Get elements from the current page with `get_element`.
@@ -156,7 +156,7 @@ For more examples
156156

157157
When you want to scale up your AI agents, we support using browsers hosted by Browserbase. This way you can run many agents in parallel without having to worry about the infrastructure.
158158

159-
To start using Browserbase just swap out the `DendriteBrowser` with `BrowserbaseBrowser` and add your Browserbase API key and project id, either in the code or in a `.env` file like this:
159+
To start using Browserbase just swap out the `AsyncDendrite` with `AsyncBrowserbaseBrowser` and add your Browserbase API key and project id, either in the code or in a `.env` file like this:
160160

161161
```bash
162162
# ... previous keys
@@ -167,14 +167,14 @@ BROWSERBASE_PROJECT_ID=
167167

168168

169169
```python
170-
# from dendrite_python_sdk import DendriteBrowser
171-
from dendrite_sdk.ext.browserbase import BrowserbaseBrowser
170+
# from dendrite_python_sdk import AsyncDendrite
171+
from dendrite_sdk.async_api.ext.browserbase import AsyncBrowserbaseBrowser
172172

173173
...
174174

175-
# browser = DendriteBrowser(...)
176-
browser = BrowserbaseBrowser(
177-
# Include the previous arguments from DendriteBrowser
175+
# browser = AsyncDendrite(...)
176+
browser = AsyncBrowserbaseBrowser(
177+
# Include the previous arguments from AsyncDendrite
178178
browserbase_api_key="...", # or specify the browsebase keys in the .env file
179179
browserbase_project_id="..."
180180
)

dendrite_sdk/__init__.py

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
from loguru import logger
2-
from ._core.dendrite_browser import DendriteBrowser
3-
from ._core.dendrite_element import DendriteElement
4-
from ._core.dendrite_page import DendritePage
5-
from ._core.models.response import DendriteElementsResponse
1+
from dendrite_sdk.async_api import (
2+
AsyncDendrite,
3+
AsyncElement,
4+
AsyncPage,
5+
AsyncElementsResponse,
6+
)
67

7-
8-
logger.disable("dendrite_python_sdk")
8+
from dendrite_sdk.sync_api import (
9+
Dendrite,
10+
Element,
11+
Page,
12+
ElementsResponse,
13+
)
914

1015
__all__ = [
11-
"DendriteBrowser",
12-
"DendriteElement",
13-
"DendritePage",
14-
"DendriteElementsResponse",
16+
"AsyncDendrite",
17+
"AsyncElement",
18+
"AsyncPage",
19+
"AsyncElementsResponse",
20+
"Dendrite",
21+
"Element",
22+
"Page",
23+
"ElementsResponse",
1524
]

dendrite_sdk/_api/dto/get_elements_dto.py

-12
This file was deleted.

dendrite_sdk/_api/dto/get_interaction_dto.py

-10
This file was deleted.

dendrite_sdk/_api/response/get_element_response.py

-11
This file was deleted.

dendrite_sdk/_exceptions/dendrite_exception.py renamed to dendrite_sdk/_common/_exceptions/dendrite_exception.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from loguru import logger
77

8-
from dendrite_sdk._exceptions._constants import INVALID_AUTH_SESSION_MSG
8+
from dendrite_sdk._common._exceptions._constants import INVALID_AUTH_SESSION_MSG
99

1010

1111
class BaseDendriteException(Exception):
@@ -50,7 +50,7 @@ class IncorrectOutcomeError(BaseDendriteException):
5050
class BrowserNotLaunchedError(BaseDendriteException):
5151
def __init__(
5252
self,
53-
message: str = "The browser should have been automatically launched by the DendriteBrowser object.. Please reach out to us on GitHub or Discord if you are facing this issue.",
53+
message: str = "The browser should have been automatically launched by the AsyncDendrite object.. Please reach out to us on GitHub or Discord if you are facing this issue.",
5454
) -> None:
5555
super().__init__(message)
5656

dendrite_sdk/_core/models/llm_config.py

-7
This file was deleted.

dendrite_sdk/_core/protocol/page_protocol.py

-24
This file was deleted.

dendrite_sdk/async_api/__init__.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from loguru import logger
2+
from ._core.dendrite_browser import AsyncDendrite
3+
from ._core.dendrite_element import AsyncElement
4+
from ._core.dendrite_page import AsyncPage
5+
from ._core.models.response import AsyncElementsResponse
6+
7+
8+
logger.disable("dendrite_python_sdk")
9+
10+
__all__ = [
11+
"AsyncDendrite",
12+
"AsyncElement",
13+
"AsyncPage",
14+
"AsyncElementsResponse",
15+
]

dendrite_sdk/_api/_http_client.py renamed to dendrite_sdk/async_api/_api/_http_client.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
from typing import Any, Optional
2-
1+
from typing import Optional
32
import httpx
43
from loguru import logger
54

65

7-
from dendrite_sdk._common.constants import DENDRITE_API_BASE_URL
6+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
7+
from dendrite_sdk.async_api._common.constants import DENDRITE_API_BASE_URL
88

99

1010
class HTTPClient:
11-
def __init__(self, api_key: Optional[str] = None, session_id: Optional[str] = None):
12-
self.api_key = api_key
11+
def __init__(self, api_config: APIConfig, session_id: Optional[str] = None):
12+
self.api_key = api_config.dendrite_api_key
1313
self.session_id = session_id
1414
self.base_url = self.resolve_base_url()
1515

dendrite_sdk/_api/browser_api_client.py renamed to dendrite_sdk/async_api/_api/browser_api_client.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
from typing import Optional
22

33
from loguru import logger
4-
from dendrite_sdk._core.models.authentication import AuthSession
5-
from dendrite_sdk._api.response.get_element_response import GetElementResponse
6-
from dendrite_sdk._api.dto.ask_page_dto import AskPageDTO
7-
from dendrite_sdk._api.dto.authenticate_dto import AuthenticateDTO
8-
from dendrite_sdk._api.dto.get_elements_dto import GetElementsDTO
9-
from dendrite_sdk._api.dto.make_interaction_dto import MakeInteractionDTO
10-
from dendrite_sdk._api.dto.scrape_page_dto import ScrapePageDTO
11-
from dendrite_sdk._api.dto.try_run_script_dto import TryRunScriptDTO
12-
from dendrite_sdk._api.dto.upload_auth_session_dto import UploadAuthSessionDTO
13-
from dendrite_sdk._api.response.ask_page_response import AskPageResponse
14-
from dendrite_sdk._api.response.interaction_response import InteractionResponse
15-
from dendrite_sdk._api.response.scrape_page_response import ScrapePageResponse
16-
from dendrite_sdk._api._http_client import HTTPClient
17-
from dendrite_sdk._exceptions.dendrite_exception import InvalidAuthSessionError
4+
from dendrite_sdk.async_api._core.models.authentication import AuthSession
5+
from dendrite_sdk.async_api._api.response.get_element_response import GetElementResponse
6+
from dendrite_sdk.async_api._api.dto.ask_page_dto import AskPageDTO
7+
from dendrite_sdk.async_api._api.dto.authenticate_dto import AuthenticateDTO
8+
from dendrite_sdk.async_api._api.dto.get_elements_dto import GetElementsDTO
9+
from dendrite_sdk.async_api._api.dto.make_interaction_dto import MakeInteractionDTO
10+
from dendrite_sdk.async_api._api.dto.scrape_page_dto import ScrapePageDTO
11+
from dendrite_sdk.async_api._api.dto.try_run_script_dto import TryRunScriptDTO
12+
from dendrite_sdk.async_api._api.dto.upload_auth_session_dto import UploadAuthSessionDTO
13+
from dendrite_sdk.async_api._api.response.ask_page_response import AskPageResponse
14+
from dendrite_sdk.async_api._api.response.interaction_response import (
15+
InteractionResponse,
16+
)
17+
from dendrite_sdk.async_api._api.response.scrape_page_response import ScrapePageResponse
18+
from dendrite_sdk.async_api._api._http_client import HTTPClient
19+
from dendrite_sdk._common._exceptions.dendrite_exception import (
20+
InvalidAuthSessionError,
21+
)
1822

1923

2024
class BrowserAPIClient(HTTPClient):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import Any, Optional
2+
from pydantic import BaseModel
3+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
4+
from dendrite_sdk.async_api._core.models.page_information import PageInformation
5+
6+
7+
class AskPageDTO(BaseModel):
8+
prompt: str
9+
return_schema: Optional[Any]
10+
page_information: PageInformation
11+
api_config: APIConfig
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import Dict, Union
2+
from pydantic import BaseModel
3+
4+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
5+
from dendrite_sdk.async_api._core.models.page_information import PageInformation
6+
7+
8+
class GetElementsDTO(BaseModel):
9+
page_information: PageInformation
10+
prompt: Union[str, Dict[str, str]]
11+
api_config: APIConfig
12+
use_cache: bool = True
13+
only_one: bool
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from pydantic import BaseModel
2+
3+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
4+
from dendrite_sdk.async_api._core.models.page_information import PageInformation
5+
6+
7+
class GetInteractionDTO(BaseModel):
8+
page_information: PageInformation
9+
api_config: APIConfig
10+
prompt: str
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from typing import Optional
2+
from pydantic import BaseModel
3+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
4+
from dendrite_sdk.async_api._core.models.page_information import PageInformation
5+
6+
7+
class GoogleSearchDTO(BaseModel):
8+
query: str
9+
country: Optional[str] = None
10+
filter_results_prompt: Optional[str] = None
11+
page_information: PageInformation
12+
api_config: APIConfig
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from typing import Literal, Optional
2+
from pydantic import BaseModel
3+
from dendrite_sdk.async_api._core.models.api_config import APIConfig
4+
from dendrite_sdk.async_api._core.models.page_diff_information import (
5+
PageDiffInformation,
6+
)
7+
8+
9+
InteractionType = Literal["click", "fill", "hover"]
10+
11+
12+
class MakeInteractionDTO(BaseModel):
13+
url: str
14+
dendrite_id: str
15+
interaction_type: InteractionType
16+
value: Optional[str] = None
17+
expected_outcome: Optional[str]
18+
page_delta_information: PageDiffInformation
19+
api_config: APIConfig

0 commit comments

Comments
 (0)