lumivor 0.1.7__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,208 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+
4
+ from langchain_core.messages import HumanMessage, SystemMessage
5
+
6
+ from lumivor.agent.views import ActionResult, AgentStepInfo
7
+ from lumivor.browser.views import BrowserState
8
+
9
+
10
+ class SystemPrompt:
11
+ def __init__(
12
+ self, action_description: str, current_date: datetime, max_actions_per_step: int = 10
13
+ ):
14
+ self.default_action_description = action_description
15
+ self.current_date = current_date
16
+ self.max_actions_per_step = max_actions_per_step
17
+
18
+ def important_rules(self) -> str:
19
+ """
20
+ Returns the important rules for the agent.
21
+ """
22
+ text = """
23
+ 1. RESPONSE FORMAT: You must ALWAYS respond with valid JSON in this exact format:
24
+ {
25
+ "current_state": {
26
+ "evaluation_previous_goal": "Success|Failed|Unknown - Analyze the current elements and the image to check if the previous goals/actions are succesful like intended by the task. Ignore the action result. The website is the ground truth. Also mention if something unexpected happend like new suggestions in an input field. Shortly state why/why not",
27
+ "memory": "Description of what has been done and what you need to remember until the end of the task",
28
+ "next_goal": "What needs to be done with the next actions"
29
+ },
30
+ "action": [
31
+ {
32
+ "action_name": {
33
+ // action-specific parameters
34
+ }
35
+ },
36
+ // ... more actions in sequence
37
+ ]
38
+ }
39
+
40
+ 2. ACTIONS: You can specify multiple actions to be executed in sequence.
41
+
42
+ Common action sequences:
43
+ - Form filling: [
44
+ {"input_text": {"index": 1, "text": "username"}},
45
+ {"input_text": {"index": 2, "text": "password"}},
46
+ {"click_element": {"index": 3}}
47
+ ]
48
+ - Navigation and extraction: [
49
+ {"open_new_tab": {}},
50
+ {"go_to_url": {"url": "https://example.com"}},
51
+ {"extract_page_content": {}}
52
+ ]
53
+
54
+
55
+ 3. ELEMENT INTERACTION:
56
+ - Only use indexes that exist in the provided element list
57
+ - Each element has a unique index number (e.g., "33[:]<button>")
58
+ - Elements marked with "_[:]" are non-interactive (for context only)
59
+
60
+ 4. NAVIGATION & ERROR HANDLING:
61
+ - If no suitable elements exist, use other functions to complete the task
62
+ - If stuck, try alternative approaches
63
+ - Handle popups/cookies by accepting or closing them
64
+ - Use scroll to find elements you are looking for
65
+
66
+ 5. TASK COMPLETION:
67
+ - Use the done action as the last action as soon as the task is complete
68
+ - Don't hallucinate actions
69
+ - If the task requires specific information - make sure to include everything in the done function. This is what the user will see.
70
+ - If you are running out of steps (current step), think about speeding it up, and ALWAYS use the done action as the last action.
71
+
72
+ 6. VISUAL CONTEXT:
73
+ - When an image is provided, use it to understand the page layout
74
+ - Bounding boxes with labels correspond to element indexes
75
+ - Each bounding box and its label have the same color
76
+ - Most often the label is inside the bounding box, on the top right
77
+ - Visual context helps verify element locations and relationships
78
+ - sometimes labels overlap, so use the context to verify the correct element
79
+
80
+ 7. Form filling:
81
+ - If you fill a input field and your action sequence is interrupted, most often a list with suggestions poped up under the field and you need to first select the right element from the suggestion list.
82
+
83
+ 8. ACTION SEQUENCING:
84
+ - Actions are executed in the order they appear in the list
85
+ - Each action should logically follow from the previous one
86
+ - If the page changes after an action, the sequence is interrupted and you get the new state.
87
+ - If content only disappears the sequence continues.
88
+ - Only provide the action sequence until you think the page will change.
89
+ - Try to be efficient, e.g. fill forms at once, or chain actions where nothing changes on the page like saving, extracting, checkboxes...
90
+ - only use multiple actions if it makes sense.
91
+ """
92
+ text += f' - use maximum {
93
+ self.max_actions_per_step} actions per sequence'
94
+ return text
95
+
96
+ def input_format(self) -> str:
97
+ return """
98
+ INPUT STRUCTURE:
99
+ 1. Current URL: The webpage you're currently on
100
+ 2. Available Tabs: List of open browser tabs
101
+ 3. Interactive Elements: List in the format:
102
+ index[:]<element_type>element_text</element_type>
103
+ - index: Numeric identifier for interaction
104
+ - element_type: HTML element type (button, input, etc.)
105
+ - element_text: Visible text or element description
106
+
107
+ Example:
108
+ 33[:]<button>Submit Form</button>
109
+ _[:] Non-interactive text
110
+
111
+
112
+ Notes:
113
+ - Only elements with numeric indexes are interactive
114
+ - _[:] elements provide context but cannot be interacted with
115
+ """
116
+
117
+ def get_system_message(self) -> SystemMessage:
118
+ """
119
+ Get the system prompt for the agent.
120
+
121
+ Returns:
122
+ str: Formatted system prompt
123
+ """
124
+ time_str = self.current_date.strftime('%Y-%m-%d %H:%M')
125
+
126
+ AGENT_PROMPT = f"""You are a precise browser automation agent that interacts with websites through structured commands. Your role is to:
127
+ 1. Analyze the provided webpage elements and structure
128
+ 2. Plan a sequence of actions to accomplish the given task
129
+ 3. Respond with valid JSON containing your action sequence and state assessment
130
+
131
+ Current date and time: {time_str}
132
+
133
+ {self.input_format()}
134
+
135
+ {self.important_rules()}
136
+
137
+ Functions:
138
+ {self.default_action_description}
139
+
140
+ Remember: Your responses must be valid JSON matching the specified format. Each action in the sequence must be valid."""
141
+ return SystemMessage(content=AGENT_PROMPT)
142
+
143
+
144
+ # Example:
145
+ # {self.example_response()}
146
+ # Your AVAILABLE ACTIONS:
147
+ # {self.default_action_description}
148
+
149
+
150
+ class AgentMessagePrompt:
151
+ def __init__(
152
+ self,
153
+ state: BrowserState,
154
+ result: Optional[List[ActionResult]] = None,
155
+ include_attributes: list[str] = [],
156
+ max_error_length: int = 400,
157
+ step_info: Optional[AgentStepInfo] = None,
158
+ ):
159
+ self.state = state
160
+ self.result = result
161
+ self.max_error_length = max_error_length
162
+ self.include_attributes = include_attributes
163
+ self.step_info = step_info
164
+
165
+ def get_user_message(self) -> HumanMessage:
166
+ if self.step_info:
167
+ step_info_description = (
168
+ f'Current step: {self.step_info.step_number +
169
+ 1}/{self.step_info.max_steps}'
170
+ )
171
+ else:
172
+ step_info_description = ''
173
+
174
+ state_description = f"""
175
+ {step_info_description}
176
+ Current url: {self.state.url}
177
+ Available tabs:
178
+ {self.state.tabs}
179
+ Interactive elements:
180
+ {self.state.element_tree.clickable_elements_to_string(include_attributes=self.include_attributes)}
181
+ """
182
+
183
+ if self.result:
184
+ for i, result in enumerate(self.result):
185
+ if result.extracted_content:
186
+ state_description += (
187
+ f'\nAction result {
188
+ i + 1}/{len(self.result)}: {result.extracted_content}'
189
+ )
190
+ if result.error:
191
+ # only use last 300 characters of error
192
+ error = result.error[-self.max_error_length:]
193
+ state_description += f'\nAction error {
194
+ i + 1}/{len(self.result)}: ...{error}'
195
+
196
+ if self.state.screenshot:
197
+ # Format message for vision model
198
+ return HumanMessage(
199
+ content=[
200
+ {'type': 'text', 'text': state_description},
201
+ {
202
+ 'type': 'image_url',
203
+ 'image_url': {'url': f'data:image/png;base64,{self.state.screenshot}'},
204
+ },
205
+ ]
206
+ )
207
+
208
+ return HumanMessage(content=state_description)