pre-commit run pre-commit-hooks --all-files

This commit is contained in:
Christian Clauss
2025-02-27 10:50:31 +01:00
parent c9641cc765
commit 4abfaa6213
39 changed files with 95 additions and 91 deletions
+1 -1
View File
@@ -81,4 +81,4 @@ body:
attributes:
label: Relevant Log Output
description: Please copy and paste any relevant log output. This will be automatically formatted into code.
render: shell
render: shell
+1 -1
View File
@@ -8,4 +8,4 @@ contact_links:
about: Please ask questions in our Discord community
- name: 📖 Documentation
url: https://docs.browser-use.com
about: Check our documentation for answers first
about: Check our documentation for answers first
+2 -2
View File
@@ -46,10 +46,10 @@ body:
description: If you have specific suggestions for how to improve the documentation, please share them
placeholder: |
The documentation could be improved by...
Example:
```python
# Your suggested code example or text here
```
validations:
required: true
required: true
+1 -1
View File
@@ -40,4 +40,4 @@ body:
placeholder: |
- Example use cases
- Screenshots or mockups
- Related issues or discussions
- Related issues or discussions
+14
View File
@@ -0,0 +1,14 @@
name: ci
on:
push:
pull_request:
workflow_dispatch:
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pre-commit run check-toml --all-files
- run: pre-commit run check-yaml --all-files
- run: pre-commit run end-of-file-fixer --all-files
- run: pre-commit run trailing-whitespace --all-files
+1 -1
View File
@@ -187,4 +187,4 @@ gcp-login.json
*.json
*.jsonl
uv.lock
uv.lock
+4 -4
View File
@@ -10,9 +10,9 @@ repos:
]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
+1 -1
View File
@@ -85,4 +85,4 @@
"justMyCode": false
}
]
}
}
+8 -12
View File
@@ -15,7 +15,7 @@
[![Weave Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fapp.workweave.ai%2Fapi%2Frepository%2Fbadge%2Forg_T5Pvn3UBswTHIsN1dWS3voPg%2F881458615&labelColor=#EC6341)](https://app.workweave.ai/reports/repository/org_T5Pvn3UBswTHIsN1dWS3voPg/881458615)
🌐 Browser-use is the easiest way to connect your AI agents with the browser.
🌐 Browser-use is the easiest way to connect your AI agents with the browser.
💡 See what others are building and share your projects in our [Discord](https://link.browser-use.com/discord) - we'd love to see what you create!
@@ -177,7 +177,7 @@ Email [Toby](mailto:tbiddle@loop11.com?subject=I%20want%20to%20join%20the%20UI/U
If you use Browser Use in your research or project, please cite:
```bibtex
@software{browser_use2024,
author = {Müller, Magnus and Žunič, Gregor},
@@ -187,20 +187,16 @@ If you use Browser Use in your research or project, please cite:
url = {https://github.com/browser-use/browser-use}
}
```
<div align="center"> <img src="https://github.com/user-attachments/assets/402b2129-b6ac-44d3-a217-01aea3277dce" width="400"/>
<div align="center"> <img src="https://github.com/user-attachments/assets/402b2129-b6ac-44d3-a217-01aea3277dce" width="400"/>
[![Twitter Follow](https://img.shields.io/twitter/follow/Gregor?style=social)](https://x.com/gregpr07)
[![Twitter Follow](https://img.shields.io/twitter/follow/Magnus?style=social)](https://x.com/mamagnus00)
</div>
</div>
<div align="center">
Made with ❤️ in Zurich and San Francisco
</div>
</div>
-1
View File
@@ -17,4 +17,3 @@ Please include as much of the information listed below as you can to help me bet
* Impact of the issue, including how an attacker might exploit the issue
This information will help me triage your report more quickly.
+4 -4
View File
@@ -48,11 +48,11 @@ Common action sequences:
5. TASK COMPLETION:
- Use the done action as the last action as soon as the ultimate task is complete
- Dont use "done" before you are done with everything the user asked you, except you reach the last step of max_steps.
- Dont use "done" before you are done with everything the user asked you, except you reach the last step of max_steps.
- If you reach your last step, use the done action even if the task is not fully finished. Provide all the information you have gathered so far. If the ultimate task is completly finished set success to true. If not everything the user asked for is completed set success in done to false!
- If you have to do something repeatedly for example the task says for "each", or "for all", or "x times", count always inside "memory" how many times you have done it and how many remain. Don't stop until you have completed like the task asked you. Only call done after the last step.
- Don't hallucinate actions
- Make sure you include everything you found out for the ultimate task in the done text parameter. Do not just say you are done, but include the requested information of the task.
- Make sure you include everything you found out for the ultimate task in the done text parameter. Do not just say you are done, but include the requested information of the task.
6. VISUAL CONTEXT:
- When an image is provided, use it to understand the page layout
@@ -62,8 +62,8 @@ Common action sequences:
- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.
8. Long tasks:
- Keep track of the status and subresults in the memory.
- Keep track of the status and subresults in the memory.
9. Extraction:
- If your task is to find information - call extract_content on the specific pages to get and store the information.
Your responses must be always JSON with the specified format.
Your responses must be always JSON with the specified format.
+12 -12
View File
@@ -674,24 +674,24 @@ class BrowserContext:
debug_script = """(() => {
function getPageStructure(element = document, depth = 0, maxDepth = 10) {
if (depth >= maxDepth) return '';
const indent = ' '.repeat(depth);
let structure = '';
// Skip certain elements that clutter the output
const skipTags = new Set(['script', 'style', 'link', 'meta', 'noscript']);
// Add current element info if it's not the document
if (element !== document) {
const tagName = element.tagName.toLowerCase();
// Skip uninteresting elements
if (skipTags.has(tagName)) return '';
const id = element.id ? `#${element.id}` : '';
const classes = element.className && typeof element.className === 'string' ?
const classes = element.className && typeof element.className === 'string' ?
`.${element.className.split(' ').filter(c => c).join('.')}` : '';
// Get additional useful attributes
const attrs = [];
if (element.getAttribute('role')) attrs.push(`role="${element.getAttribute('role')}"`);
@@ -702,10 +702,10 @@ class BrowserContext:
const src = element.getAttribute('src');
attrs.push(`src="${src.substring(0, 50)}${src.length > 50 ? '...' : ''}"`);
}
// Add element info
structure += `${indent}${tagName}${id}${classes}${attrs.length ? ' [' + attrs.join(', ') + ']' : ''}\\n`;
// Handle iframes specially
if (tagName === 'iframe') {
try {
@@ -721,7 +721,7 @@ class BrowserContext:
}
}
}
// Get all child elements
const children = element.children || element.childNodes;
for (const child of children) {
@@ -729,10 +729,10 @@ class BrowserContext:
structure += getPageStructure(child, depth + 1, maxDepth);
}
}
return structure;
}
return getPageStructure();
})()"""
+1 -1
View File
@@ -128,7 +128,7 @@ documentation](https://playwright.dev/docs/api/class-browsercontext).
The agent is executed using the async `run()` method:
- `max_steps` (default: `100`)
- `max_steps` (default: `100`)
Maximum number of steps the agent can take during execution. This prevents infinite loops and helps control execution time.
## Agent History
-1
View File
@@ -125,4 +125,3 @@ controller = Controller(exclude_actions=['open_tab', 'search_google'])
For more examples like file upload or notifications, visit [examples/custom-functions](https://github.com/browser-use/browser-use/tree/main/examples/custom-functions).
+1 -1
View File
@@ -47,4 +47,4 @@ async def main():
if __name__ == '__main__':
asyncio.run(main())
```
```
+2 -2
View File
@@ -43,8 +43,8 @@ if __name__ == '__main__':
In this example:
1. The model only sees `x_name` and `x_password` as placeholders.
2. When the model wants to use your password it outputs x_password - and we replace it with the actual value.
3. When your password is visable on the current page, we replace it in the LLM input - so that the model never has it in its state.
3. When your password is visable on the current page, we replace it in the LLM input - so that the model never has it in its state.
Warning: Vision models still see the image of the page - where the sensitive data might be visible.
This approach ensures that sensitive information remains secure while still allowing the agent to perform tasks that require authentication.
This approach ensures that sensitive information remains secure while still allowing the agent to perform tasks that require authentication.
+2 -2
View File
@@ -138,7 +138,7 @@ GEMINI_API_KEY=
### DeepSeek-V3
The community likes DeepSeek-V3 for its low price, no rate limits, open-source nature, and good performance.
The community likes DeepSeek-V3 for its low price, no rate limits, open-source nature, and good performance.
The example is available [here](https://github.com/browser-use/browser-use/blob/main/examples/models/deepseek.py).
```python
@@ -192,7 +192,7 @@ DEEPSEEK_API_KEY=
```
### Ollama
Many users asked for local models. Here they are.
Many users asked for local models. Here they are.
1. Download Ollama from [here](https://ollama.ai/download)
2. Run `ollama pull model_name`. Pick a model which supports tool-calling from [here](https://ollama.com/search?c=tools)
+1 -1
View File
@@ -98,7 +98,7 @@ We suggest using extensions on your IDE to recognize and format MDX. If you're a
</Accordion>
<Accordion title="Issue: Encountering an unknown error">
Solution: Go to the root of your device and delete the \~/.mintlify folder. Afterwards, run `mintlify dev` again.
</Accordion>
</AccordionGroup>
+1 -1
View File
@@ -63,4 +63,4 @@ In the trace view, you can also see the agent's current step, the tool it's usin
## Laminar
To learn more about tracing and evaluating your browser agents, check out the [Laminar docs](https://docs.lmnr.ai).
To learn more about tracing and evaluating your browser agents, check out the [Laminar docs](https://docs.lmnr.ai).
+1 -1
View File
@@ -73,4 +73,4 @@ To run this example, you need to install the following packages:
You can install these packages using pip:
```sh
pip install fastapi uvicorn slack_sdk
pip install fastapi uvicorn slack_sdk
+2 -2
View File
@@ -20,7 +20,7 @@ class SlackBot:
def __init__(self, llm: BaseChatModel, bot_token: str, signing_secret: str, ack: bool = False, browser_config: BrowserConfig = BrowserConfig(headless=True)):
if not bot_token or not signing_secret:
raise ValueError("Bot token and signing secret must be provided")
self.llm = llm
self.ack = ack
self.browser_config = browser_config
@@ -108,4 +108,4 @@ async def slack_events(request: Request, slack_bot: SlackBot = Depends()):
return {}
except Exception as e:
logger.error(f"Error in slack_events: {str(e)}")
raise HTTPException(status_code=500, detail="Internal Server Error")
raise HTTPException(status_code=500, detail="Internal Server Error")
+2 -2
View File
@@ -21,7 +21,7 @@ azure_openai_endpoint = os.environ.get('AZURE_OPENAI_ENDPOINT')
# Initialize the Azure OpenAI client
llm = AzureChatOpenAI(
model_name='gpt-4o',
model_name='gpt-4o',
openai_api_key=azure_openai_api_key,
azure_endpoint=azure_openai_endpoint, # Corrected to use azure_endpoint instead of openai_api_base
deployment_name='gpt-4o', # Use deployment_name for Azure models
@@ -39,4 +39,4 @@ async def main():
input('Press Enter to continue...')
asyncio.run(main())
asyncio.run(main())
+1 -1
View File
@@ -757,4 +757,4 @@
]
}
]
}
}
+1 -1
View File
@@ -4,4 +4,4 @@
|------------------------|-------------------|-------------------------------------------|-------------------------------------------|
| `command_line.py` | **Terminal** | Parses arguments for command-line execution. | `python command_line.py` |
| `gradio_demo.py` | **Gradio** | Provides a Gradio-based interactive UI. | `python gradio_demo.py` |
| `streamlit_demo.py` | **Streamlit** | Runs a Streamlit-based web interface. | `python -m streamlit run streamlit_demo.py` |
| `streamlit_demo.py` | **Streamlit** | Runs a Streamlit-based web interface. | `python -m streamlit run streamlit_demo.py` |
+4 -4
View File
@@ -34,7 +34,7 @@ def get_llm(provider: str):
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
raise ValueError("Error: ANTHROPIC_API_KEY is not set. Please provide a valid API key.")
return ChatAnthropic(
model_name='claude-3-5-sonnet-20240620', timeout=25, stop=None, temperature=0.0
)
@@ -43,7 +43,7 @@ def get_llm(provider: str):
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("Error: OPENAI_API_KEY is not set. Please provide a valid API key.")
return ChatOpenAI(model='gpt-4o', temperature=0.0)
else:
@@ -88,10 +88,10 @@ async def main():
agent, browser = initialize_agent(args.query, args.provider)
await agent.run(max_steps=25)
input('Press Enter to close the browser...')
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
+1 -1
View File
@@ -105,4 +105,4 @@ def create_ui():
if __name__ == '__main__':
demo = create_ui()
demo.launch()
demo.launch()
+2 -2
View File
@@ -29,7 +29,7 @@ def get_llm(provider: str):
if not api_key:
st.error("Error: ANTHROPIC_API_KEY is not set. Please provide a valid API key.")
st.stop()
return ChatAnthropic(
model_name='claude-3-5-sonnet-20240620', timeout=25, stop=None, temperature=0.0
)
@@ -39,7 +39,7 @@ def get_llm(provider: str):
if not api_key:
st.error("Error: OPENAI_API_KEY is not set. Please provide a valid API key.")
st.stop()
return ChatOpenAI(model='gpt-4o', temperature=0.0)
else:
st.error(f'Unsupported provider: {provider}')
-3
View File
@@ -10,6 +10,3 @@
| `scrolling_page.py` | Automates webpage scrolling with various scrolling actions and text search functionality. |
| `twitter_post_using_cookies.py` | Automates posting on X (Twitter) using stored authentication cookies. |
| `web_voyager_agent.py` | A general-purpose web navigation agent for tasks like flight booking and course searching. |
+1 -1
View File
@@ -33,4 +33,4 @@ async def main():
input('Press Enter to exit')
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
+2 -2
View File
@@ -1,5 +1,5 @@
"""
Goal: Searches for job listings, evaluates relevance based on a CV, and applies
Goal: Searches for job listings, evaluates relevance based on a CV, and applies
@dev You need to add OPENAI_API_KEY to your environment variables.
Also you have to install PyPDF2 to read pdf files: pip install PyPDF2
@@ -157,4 +157,4 @@ async def main():
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
+1 -1
View File
@@ -43,4 +43,4 @@ async def main():
await coder.run()
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
+1 -1
View File
@@ -124,4 +124,4 @@ async def main():
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
+3 -3
View File
@@ -8,7 +8,7 @@ import asyncio
task="""
### Prompt for Shopping Agent Migros Online Grocery Order
**Objective:**
**Objective:**
Visit [Migros Online](https://www.migros.ch/en), search for the required grocery items, add them to the cart, select an appropriate delivery window, and complete the checkout process using TWINT.
**Important:**
@@ -89,8 +89,8 @@ At this stage, check the basket on the top right (indicates the price) and check
- Proceed to checkout.
- Select **TWINT** as the payment method.
- Check out.
-
- if it's needed the userename is: nikoskalio.dev@gmail.com
-
- if it's needed the userename is: nikoskalio.dev@gmail.com
- and the password is : TheCircuit.Migros.dev!
---
@@ -1,4 +1,4 @@
# Goal: Automates posting on X (Twitter) using stored authentication cookies.
# Goal: Automates posting on X (Twitter) using stored authentication cookies.
import asyncio
import os
+3 -3
View File
@@ -35,7 +35,7 @@ async def test_standard_browser_launch(monkeypatch):
@pytest.mark.asyncio
async def test_cdp_browser_launch(monkeypatch):
"""
Test that when a CDP URL is provided in the configuration, the Browser uses _setup_cdp
Test that when a CDP URL is provided in the configuration, the Browser uses _setup_cdp
and returns the expected DummyBrowser.
"""
class DummyBrowser:
@@ -87,7 +87,7 @@ async def test_wss_browser_launch(monkeypatch):
@pytest.mark.asyncio
async def test_chrome_instance_browser_launch(monkeypatch):
"""
Test that when a chrome instance path is provided the Browser class uses
Test that when a chrome instance path is provided the Browser class uses
_setup_browser_with_instance branch and returns the expected DummyBrowser object
by reusing an existing Chrome instance.
"""
@@ -303,4 +303,4 @@ async def test_standard_browser_launch_with_proxy(monkeypatch):
# Call get_playwright_browser and verify that the returned browser is as expected.
result_browser = await browser_obj.get_playwright_browser()
assert isinstance(result_browser, DummyBrowser), "Expected DummyBrowser from _setup_standard_browser with proxy provided"
await browser_obj.close()
await browser_obj.close()
+3 -3
View File
@@ -9,7 +9,7 @@ from unittest.mock import Mock
def test_is_url_allowed():
"""
Test the _is_url_allowed method to verify that it correctly checks URLs against
Test the _is_url_allowed method to verify that it correctly checks URLs against
the allowed domains configuration.
Scenario 1: When allowed_domains is None, all URLs should be allowed.
Scenario 2: When allowed_domains is a list, only URLs matching the allowed domain(s) are allowed.
@@ -151,7 +151,7 @@ async def test_get_scroll_info():
"""
Test the get_scroll_info method by mocking the page's evaluate method.
This dummy page returns preset values for window.scrollY, window.innerHeight,
and document.documentElement.scrollHeight. The test then verifies that the
and document.documentElement.scrollHeight. The test then verifies that the
computed scroll information (pixels_above and pixels_below) match the expected values.
"""
# Define a dummy page with an async evaluate method returning preset values.
@@ -323,4 +323,4 @@ async def test_remove_highlights_failure():
try:
await context.remove_highlights()
except Exception as e:
pytest.fail(f"remove_highlights raised an exception: {e}")
pytest.fail(f"remove_highlights raised an exception: {e}")
+4 -4
View File
@@ -19,18 +19,18 @@ async def test_dropdown(llm, browser_context):
try:
history: AgentHistoryList = await agent.run(20)
result = history.final_result()
# Verify dropdown interaction
assert result is not None
assert 'Duck' in result, "Expected 5th option 'Duck' to be selected"
# Verify dropdown state
element = await browser_context.get_element_by_selector('select')
assert element is not None, "Dropdown element should exist"
value = await element.evaluate('el => el.value')
assert value == '5', "Dropdown should have 5th option selected"
except Exception as e:
pytest.fail(f"Dropdown test failed: {str(e)}")
finally:
+5 -5
View File
@@ -19,22 +19,22 @@ async def test_dropdown_complex(llm, browser_context):
try:
history: AgentHistoryList = await agent.run(20)
result = history.final_result()
# Verify dropdown interaction
assert result is not None
assert 'json' in result.lower(), "Expected 'json' option to be selected"
# Verify dropdown state
element = await browser_context.get_element_by_selector('.select-selected')
assert element is not None, "Custom dropdown element should exist"
text = await element.text_content()
assert 'json' in text.lower(), "Dropdown should display json option"
# Verify the selected option's effect
code_element = await browser_context.get_element_by_selector('pre code')
assert code_element is not None, "Code element should be visible when JSON is selected"
except Exception as e:
pytest.fail(f"Complex dropdown test failed: {str(e)}")
finally:
-1
View File
@@ -40,4 +40,3 @@ async def test_gif_path():
assert result is not None
assert os.path.exists("./google.gif"), "google.gif was not created"