Skip to content

Commit 9751d92

Browse files
Merge pull request #244 from askui/feat/max_steps
Adds max_steps parameter to stop the execution after a predefined number of steps
2 parents b2a28e1 + ef178b7 commit 9751d92

12 files changed

Lines changed: 36 additions & 10 deletions

File tree

docs/11_callbacks.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Callbacks provide hooks into the agent's conversation lifecycle, similar to PyTorch Lightning's callback system. Use them for logging, monitoring, custom metrics, or extending agent behavior.
44

5+
All callbacks live in `askui.callbacks` and can be imported from there.
6+
57
## Usage
68

79
Subclass `ConversationCallback` and override the hooks you need:
@@ -71,6 +73,10 @@ with ComputerAgent(callbacks=[TimingCallback()]) as agent:
7173
agent.act("Search for documents")
7274
```
7375

76+
## Built-in Callbacks
77+
78+
(we will add built-in callbacks at a later stage)
79+
7480
## Multiple Callbacks
7581

7682
Pass multiple callbacks to combine behaviors:

src/askui/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from .agent_base import Agent
1111
from .agent_settings import AgentSettings
12+
from .callbacks import ConversationCallback
1213
from .computer_agent import ComputerAgent, VisionAgent
1314
from .locators import Locator
1415
from .models import (
@@ -30,7 +31,6 @@
3031
ToolUseBlockParam,
3132
UrlImageSourceParam,
3233
)
33-
from .models.shared.conversation_callback import ConversationCallback
3434
from .models.shared.settings import (
3535
DEFAULT_GET_RESOLUTION,
3636
DEFAULT_LOCATE_RESOLUTION,

src/askui/agent_base.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
from typing_extensions import Self
1111

1212
from askui.agent_settings import AgentSettings
13+
from askui.callbacks import ConversationCallback, UsageTrackingCallback
1314
from askui.container import telemetry
1415
from askui.locators.locators import Locator
1516
from askui.models.shared.agent_message_param import MessageParam
1617
from askui.models.shared.conversation import Conversation, Speakers
17-
from askui.models.shared.conversation_callback import ConversationCallback
1818
from askui.models.shared.settings import (
1919
ActSettings,
2020
CacheWritingSettings,
@@ -23,7 +23,6 @@
2323
LocateSettings,
2424
)
2525
from askui.models.shared.tools import Tool, ToolCollection
26-
from askui.models.shared.usage_tracking_callback import UsageTrackingCallback
2726
from askui.prompts.act_prompts import CACHE_USE_PROMPT, create_default_prompt
2827
from askui.telemetry.otel import OtelSettings, setup_opentelemetry_tracing
2928
from askui.tools.agent_os import AgentOs

src/askui/android_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
from askui.agent_base import Agent
88
from askui.agent_settings import AgentSettings
9+
from askui.callbacks import ConversationCallback
910
from askui.container import telemetry
1011
from askui.locators.locators import Locator
1112
from askui.models.models import Point
12-
from askui.models.shared.conversation_callback import ConversationCallback
1313
from askui.models.shared.settings import ActSettings, MessageSettings
1414
from askui.models.shared.tools import Tool
1515
from askui.prompts.act_prompts import create_android_agent_prompt

src/askui/callbacks/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .conversation_callback import ConversationCallback
2+
from .usage_tracking_callback import UsageTrackingCallback
3+
4+
__all__ = [
5+
"ConversationCallback",
6+
"UsageTrackingCallback",
7+
]
File renamed without changes.

src/askui/models/shared/usage_tracking_callback.py renamed to src/askui/callbacks/usage_tracking_callback.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pydantic import BaseModel
99
from typing_extensions import override
1010

11-
from askui.models.shared.conversation_callback import ConversationCallback
11+
from askui.callbacks.conversation_callback import ConversationCallback
1212
from askui.reporting import NULL_REPORTER
1313

1414
if TYPE_CHECKING:

src/askui/computer_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
from askui.agent_base import Agent
88
from askui.agent_settings import AgentSettings
9+
from askui.callbacks import ConversationCallback
910
from askui.container import telemetry
1011
from askui.locators.locators import Locator
1112
from askui.models.models import Point
12-
from askui.models.shared.conversation_callback import ConversationCallback
1313
from askui.models.shared.settings import ActSettings, LocateSettings, MessageSettings
1414
from askui.models.shared.tools import Tool
1515
from askui.prompts.act_prompts import (

src/askui/models/shared/conversation.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from askui.tools.switch_speaker_tool import SwitchSpeakerTool
2323

2424
if TYPE_CHECKING:
25-
from askui.models.shared.conversation_callback import ConversationCallback
25+
from askui.callbacks import ConversationCallback
2626
from askui.utils.caching.cache_manager import CacheManager
2727

2828
logger = logging.getLogger(__name__)
@@ -208,8 +208,21 @@ def _execute_control_loop(self) -> None:
208208
continue_execution = True
209209
while continue_execution:
210210
continue_execution = self._execute_step()
211+
if self._is_max_steps_reached():
212+
continue_execution = False
211213
self._on_control_loop_end()
212214

215+
def _is_max_steps_reached(self) -> bool:
216+
if self.settings.max_steps is None:
217+
return False
218+
if self._step_index >= self.settings.max_steps:
219+
msg = (
220+
f"Reached max_steps limit {self.settings.max_steps}, stopping execution"
221+
)
222+
logger.exception(msg)
223+
return True
224+
return False
225+
213226
@tracer.start_as_current_span("_teardown_control_loop")
214227
def _teardown_control_loop(self) -> None:
215228
# Finish recording if cache_manager is active and not executing from cache

src/askui/models/shared/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class ActSettings(BaseModel):
8989
model_config = ConfigDict(arbitrary_types_allowed=True)
9090

9191
messages: MessageSettings = Field(default_factory=MessageSettings)
92+
max_steps: int | None = None
9293

9394

9495
class GetSettings(BaseModel):

0 commit comments

Comments
 (0)