Spaces:
Paused
Paused
frdel commited on
Commit ·
0d362e5
1
Parent(s): dcd3ab7
browser-use intervention hack
Browse files- README.md +2 -1
- docs/res/favicon.png +3 -0
- docs/res/favicon_round.png +3 -0
- python/extensions/message_loop_prompts/.gitkeep +0 -0
- python/extensions/message_loop_start/.gitkeep +0 -0
- python/extensions/message_loop_start/_10_iteration_no.py +14 -0
- python/extensions/monologue_end/.gitkeep +0 -0
- python/extensions/system_prompt/.gitkeep +0 -0
- python/tools/browser_agent.py +38 -3
- webui/index.html +1 -1
- webui/public/favicon_round.svg +15 -0
README.md
CHANGED
|
@@ -4,7 +4,8 @@
|
|
| 4 |
|
| 5 |
# `Agent Zero`
|
| 6 |
|
| 7 |
-
[](https://www.skool.com/agent-zero) [](https://discord.gg/B8KZKNsPpj) [](https://www.youtube.com/@AgentZeroFW) [](https://www.linkedin.com/in/jan-tomasek/) [](https://x.com/JanTomasekDev)
|
|
|
|
| 8 |
|
| 9 |
[Installation](./docs/installation.md) •
|
| 10 |
[How to update](./docs/installation.md#how-to-update-agent-zero) •
|
|
|
|
| 4 |
|
| 5 |
# `Agent Zero`
|
| 6 |
|
| 7 |
+
[](https://github.com/sponsors/frdel) [](https://www.skool.com/agent-zero) [](https://discord.gg/B8KZKNsPpj) [](https://www.youtube.com/@AgentZeroFW) [](https://www.linkedin.com/in/jan-tomasek/) [](https://x.com/JanTomasekDev)
|
| 8 |
+
|
| 9 |
|
| 10 |
[Installation](./docs/installation.md) •
|
| 11 |
[How to update](./docs/installation.md#how-to-update-agent-zero) •
|
docs/res/favicon.png
ADDED
|
|
Git LFS Details
|
docs/res/favicon_round.png
ADDED
|
|
Git LFS Details
|
python/extensions/message_loop_prompts/.gitkeep
ADDED
|
File without changes
|
python/extensions/message_loop_start/.gitkeep
ADDED
|
File without changes
|
python/extensions/message_loop_start/_10_iteration_no.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from python.helpers.extension import Extension
|
| 2 |
+
from agent import Agent, LoopData
|
| 3 |
+
|
| 4 |
+
DATA_NAME_ITER_NO = "iteration_no"
|
| 5 |
+
|
| 6 |
+
class IterationNo(Extension):
|
| 7 |
+
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 8 |
+
# total iteration number
|
| 9 |
+
no = self.agent.get_data(DATA_NAME_ITER_NO) or 0
|
| 10 |
+
self.agent.set_data(DATA_NAME_ITER_NO, no + 1)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def get_iter_no(agent: Agent) -> int:
|
| 14 |
+
return agent.get_data(DATA_NAME_ITER_NO) or 0
|
python/extensions/monologue_end/.gitkeep
ADDED
|
File without changes
|
python/extensions/system_prompt/.gitkeep
ADDED
|
File without changes
|
python/tools/browser_agent.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
| 1 |
import asyncio
|
| 2 |
import json
|
| 3 |
import time
|
| 4 |
-
from agent import Agent
|
| 5 |
|
| 6 |
import models
|
| 7 |
from python.helpers.tool import Tool, Response
|
| 8 |
from python.helpers import dirty_json, files, rfc_exchange, defer, strings, persist_chat
|
| 9 |
from python.helpers.print_style import PrintStyle
|
| 10 |
from python.helpers.browser_use import browser_use
|
|
|
|
| 11 |
from pydantic import BaseModel
|
| 12 |
import uuid
|
| 13 |
|
|
@@ -24,6 +25,8 @@ class State:
|
|
| 24 |
self.task = None
|
| 25 |
self.use_agent = None
|
| 26 |
self.browser = None
|
|
|
|
|
|
|
| 27 |
|
| 28 |
def __del__(self):
|
| 29 |
self.kill_task()
|
|
@@ -42,6 +45,9 @@ class State:
|
|
| 42 |
# Await the coroutine to get the browser context
|
| 43 |
self.context = await self.browser.new_context()
|
| 44 |
|
|
|
|
|
|
|
|
|
|
| 45 |
# Add init script to the context - this will be applied to all new pages
|
| 46 |
await self.context._initialize_session()
|
| 47 |
pw_context = self.context.session.context # type: ignore
|
|
@@ -68,6 +74,7 @@ class State:
|
|
| 68 |
self.context = None
|
| 69 |
self.use_agent = None
|
| 70 |
self.browser = None
|
|
|
|
| 71 |
|
| 72 |
async def _run_task(self, task: str):
|
| 73 |
|
|
@@ -117,9 +124,34 @@ class State:
|
|
| 117 |
system_prompt_class=CustomSystemPrompt,
|
| 118 |
controller=controller,
|
| 119 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
result = await self.use_agent.run()
|
| 121 |
return result
|
| 122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
async def get_page(self):
|
| 124 |
if self.use_agent:
|
| 125 |
return await self.use_agent.browser_context.get_current_page()
|
|
@@ -150,8 +182,11 @@ class BrowserAgent(Tool):
|
|
| 150 |
# collect result
|
| 151 |
result = await task.result()
|
| 152 |
answer = result.final_result()
|
| 153 |
-
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
| 155 |
self.log.update(answer=answer_text)
|
| 156 |
return Response(message=answer, break_loop=False)
|
| 157 |
|
|
|
|
| 1 |
import asyncio
|
| 2 |
import json
|
| 3 |
import time
|
| 4 |
+
from agent import Agent, InterventionException
|
| 5 |
|
| 6 |
import models
|
| 7 |
from python.helpers.tool import Tool, Response
|
| 8 |
from python.helpers import dirty_json, files, rfc_exchange, defer, strings, persist_chat
|
| 9 |
from python.helpers.print_style import PrintStyle
|
| 10 |
from python.helpers.browser_use import browser_use
|
| 11 |
+
from python.extensions.message_loop_start._10_iteration_no import get_iter_no
|
| 12 |
from pydantic import BaseModel
|
| 13 |
import uuid
|
| 14 |
|
|
|
|
| 25 |
self.task = None
|
| 26 |
self.use_agent = None
|
| 27 |
self.browser = None
|
| 28 |
+
self.iter_no = 0
|
| 29 |
+
|
| 30 |
|
| 31 |
def __del__(self):
|
| 32 |
self.kill_task()
|
|
|
|
| 45 |
# Await the coroutine to get the browser context
|
| 46 |
self.context = await self.browser.new_context()
|
| 47 |
|
| 48 |
+
# override async methods to create hooks
|
| 49 |
+
self.override_hooks()
|
| 50 |
+
|
| 51 |
# Add init script to the context - this will be applied to all new pages
|
| 52 |
await self.context._initialize_session()
|
| 53 |
pw_context = self.context.session.context # type: ignore
|
|
|
|
| 74 |
self.context = None
|
| 75 |
self.use_agent = None
|
| 76 |
self.browser = None
|
| 77 |
+
self.iter_no = 0
|
| 78 |
|
| 79 |
async def _run_task(self, task: str):
|
| 80 |
|
|
|
|
| 124 |
system_prompt_class=CustomSystemPrompt,
|
| 125 |
controller=controller,
|
| 126 |
)
|
| 127 |
+
|
| 128 |
+
self.iter_no = get_iter_no(self.agent)
|
| 129 |
+
|
| 130 |
+
# orig_err_hnd = self.use_agent._handle_step_error
|
| 131 |
+
# def new_err_hnd(*args, **kwargs):
|
| 132 |
+
# if isinstance(args[0], InterventionException):
|
| 133 |
+
# raise args[0]
|
| 134 |
+
# return orig_err_hnd(*args, **kwargs)
|
| 135 |
+
# self.use_agent._handle_step_error = new_err_hnd
|
| 136 |
+
|
| 137 |
result = await self.use_agent.run()
|
| 138 |
return result
|
| 139 |
|
| 140 |
+
def override_hooks(self):
|
| 141 |
+
# override async function to create a hook
|
| 142 |
+
def override_hook(func):
|
| 143 |
+
async def wrapper(*args, **kwargs):
|
| 144 |
+
await self.agent.wait_if_paused()
|
| 145 |
+
if self.iter_no != get_iter_no(self.agent):
|
| 146 |
+
raise InterventionException("Task cancelled")
|
| 147 |
+
return await func(*args, **kwargs)
|
| 148 |
+
return wrapper
|
| 149 |
+
|
| 150 |
+
if self.context:
|
| 151 |
+
self.context.get_state = override_hook(self.context.get_state)
|
| 152 |
+
self.context.get_session = override_hook(self.context.get_session)
|
| 153 |
+
self.context.remove_highlights = override_hook(self.context.remove_highlights)
|
| 154 |
+
|
| 155 |
async def get_page(self):
|
| 156 |
if self.use_agent:
|
| 157 |
return await self.use_agent.browser_context.get_current_page()
|
|
|
|
| 182 |
# collect result
|
| 183 |
result = await task.result()
|
| 184 |
answer = result.final_result()
|
| 185 |
+
try:
|
| 186 |
+
answer_data = dirty_json.DirtyJson.parse_string(answer)
|
| 187 |
+
answer_text = strings.dict_to_text(answer_data) # type: ignore
|
| 188 |
+
except Exception as e:
|
| 189 |
+
answer_text = answer
|
| 190 |
self.log.update(answer=answer_text)
|
| 191 |
return Response(message=answer, break_loop=False)
|
| 192 |
|
webui/index.html
CHANGED
|
@@ -457,7 +457,7 @@
|
|
| 457 |
<div :class="{'field': true, 'field-full': field.type === 'textarea'}">
|
| 458 |
<div class="field-label">
|
| 459 |
<div class="field-title" x-text="field.title"></div>
|
| 460 |
-
<div class="field-description" x-html="field.description"></div>
|
| 461 |
</div>
|
| 462 |
|
| 463 |
<div class="field-control">
|
|
|
|
| 457 |
<div :class="{'field': true, 'field-full': field.type === 'textarea'}">
|
| 458 |
<div class="field-label">
|
| 459 |
<div class="field-title" x-text="field.title"></div>
|
| 460 |
+
<div class="field-description" x-html="field.description || ''"></div>
|
| 461 |
</div>
|
| 462 |
|
| 463 |
<div class="field-control">
|
webui/public/favicon_round.svg
ADDED
|
|