kolega-code 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kolega_code/__init__.py +151 -0
- kolega_code/agent/__init__.py +42 -0
- kolega_code/agent/baseagent.py +998 -0
- kolega_code/agent/browseragent.py +123 -0
- kolega_code/agent/coder.py +157 -0
- kolega_code/agent/common.py +41 -0
- kolega_code/agent/compression.py +81 -0
- kolega_code/agent/context.py +112 -0
- kolega_code/agent/conversation.py +408 -0
- kolega_code/agent/generalagent.py +146 -0
- kolega_code/agent/investigationagent.py +123 -0
- kolega_code/agent/planningagent.py +187 -0
- kolega_code/agent/prompt_provider.py +196 -0
- kolega_code/agent/prompt_templates/agents/browser.j2 +102 -0
- kolega_code/agent/prompt_templates/agents/coder_cli_mode.j2 +127 -0
- kolega_code/agent/prompt_templates/agents/general.j2 +68 -0
- kolega_code/agent/prompt_templates/agents/investigation.j2 +72 -0
- kolega_code/agent/prompt_templates/common/frontend_guidance.md +36 -0
- kolega_code/agent/prompt_templates/common/kolega_md_instructions.md +14 -0
- kolega_code/agent/prompt_templates/environment_variables/workspace_env_vars.md +11 -0
- kolega_code/agent/prompt_templates/template_guidance/expo-template.md +379 -0
- kolega_code/agent/prompt_templates/template_guidance/html-website-template.md +3 -0
- kolega_code/agent/prompt_templates/template_guidance/mern-stack-template.md +3 -0
- kolega_code/agent/prompt_templates/template_guidance/react-vite-shadcdn-template.md +182 -0
- kolega_code/agent/prompts.py +192 -0
- kolega_code/agent/tests/__init__.py +0 -0
- kolega_code/agent/tests/llm/__init__.py +0 -0
- kolega_code/agent/tests/llm/test_anthropic_token_counting.py +633 -0
- kolega_code/agent/tests/llm/test_billing_openai_cache.py +74 -0
- kolega_code/agent/tests/llm/test_client.py +773 -0
- kolega_code/agent/tests/llm/test_dashscope_mapping.py +32 -0
- kolega_code/agent/tests/llm/test_error_boundary.py +322 -0
- kolega_code/agent/tests/llm/test_exceptions.py +249 -0
- kolega_code/agent/tests/llm/test_instrumented_client.py +536 -0
- kolega_code/agent/tests/llm/test_instrumented_client_integration.py +547 -0
- kolega_code/agent/tests/llm/test_langfuse_normalization.py +39 -0
- kolega_code/agent/tests/llm/test_model_specs.py +17 -0
- kolega_code/agent/tests/llm/test_openai_cached_tokens.py +58 -0
- kolega_code/agent/tests/llm/test_openai_cached_tokens_stream.py +74 -0
- kolega_code/agent/tests/llm/test_openai_message_conversion.py +30 -0
- kolega_code/agent/tests/llm/test_openai_token_counting.py +687 -0
- kolega_code/agent/tests/llm/test_tool_execution_ids.py +193 -0
- kolega_code/agent/tests/services/__init__.py +1 -0
- kolega_code/agent/tests/services/test_browser.py +447 -0
- kolega_code/agent/tests/services/test_browser_parity.py +353 -0
- kolega_code/agent/tests/services/test_file_system.py +699 -0
- kolega_code/agent/tests/services/test_sandbox_terminal_input.py +98 -0
- kolega_code/agent/tests/services/test_terminal.py +154 -0
- kolega_code/agent/tests/services/test_terminal_command_tracking.py +385 -0
- kolega_code/agent/tests/services/test_terminal_state_serializer.py +262 -0
- kolega_code/agent/tests/test_agent_tools_inventory.py +267 -0
- kolega_code/agent/tests/test_base_agent.py +1942 -0
- kolega_code/agent/tests/test_coder_attachments.py +330 -0
- kolega_code/agent/tests/test_coder_prompt_extensions.py +61 -0
- kolega_code/agent/tests/test_commands.py +179 -0
- kolega_code/agent/tests/test_duplicate_tool_results.py +556 -0
- kolega_code/agent/tests/test_empty_message_handling.py +48 -0
- kolega_code/agent/tests/test_general_agent.py +242 -0
- kolega_code/agent/tests/test_html.py +320 -0
- kolega_code/agent/tests/test_parallel_tool_calls.py +291 -0
- kolega_code/agent/tests/test_planning_agent.py +227 -0
- kolega_code/agent/tests/test_prompt_provider.py +271 -0
- kolega_code/agent/tests/test_tool_registry.py +102 -0
- kolega_code/agent/tests/test_tools.py +549 -0
- kolega_code/agent/tests/tool_backend/__init__.py +0 -0
- kolega_code/agent/tests/tool_backend/test_agent_tool.py +356 -0
- kolega_code/agent/tests/tool_backend/test_base_tool.py +147 -0
- kolega_code/agent/tests/tool_backend/test_browser_tool.py +335 -0
- kolega_code/agent/tests/tool_backend/test_build_tool.py +93 -0
- kolega_code/agent/tests/tool_backend/test_create_file_tool.py +115 -0
- kolega_code/agent/tests/tool_backend/test_glob_tool.py +196 -0
- kolega_code/agent/tests/tool_backend/test_glob_tool_sandbox_parity.py +230 -0
- kolega_code/agent/tests/tool_backend/test_list_directory_tool.py +292 -0
- kolega_code/agent/tests/tool_backend/test_read_file_tool.py +173 -0
- kolega_code/agent/tests/tool_backend/test_replace_entire_file_tool.py +115 -0
- kolega_code/agent/tests/tool_backend/test_replace_lines_tool.py +141 -0
- kolega_code/agent/tests/tool_backend/test_search_and_replace_tool.py +174 -0
- kolega_code/agent/tests/tool_backend/test_search_codebase_tool.py +228 -0
- kolega_code/agent/tests/tool_backend/test_terminal_tool.py +482 -0
- kolega_code/agent/tests/tool_backend/test_think_hard_integration.py +189 -0
- kolega_code/agent/tests/tool_backend/test_think_hard_streaming.py +445 -0
- kolega_code/agent/tests/tool_backend/test_web_fetch_tool.py +194 -0
- kolega_code/agent/tool_backend/agent_tool.py +414 -0
- kolega_code/agent/tool_backend/apply_edit_tool.py +98 -0
- kolega_code/agent/tool_backend/apply_patch_tool.py +514 -0
- kolega_code/agent/tool_backend/base_tool.py +217 -0
- kolega_code/agent/tool_backend/browser_tool.py +271 -0
- kolega_code/agent/tool_backend/build_tool.py +93 -0
- kolega_code/agent/tool_backend/create_file_tool.py +52 -0
- kolega_code/agent/tool_backend/glob_tool.py +323 -0
- kolega_code/agent/tool_backend/list_directory_tool.py +300 -0
- kolega_code/agent/tool_backend/memory_tool.py +79 -0
- kolega_code/agent/tool_backend/read_file_tool.py +119 -0
- kolega_code/agent/tool_backend/replace_entire_file_tool.py +40 -0
- kolega_code/agent/tool_backend/replace_lines_tool.py +97 -0
- kolega_code/agent/tool_backend/search_and_replace_tool.py +146 -0
- kolega_code/agent/tool_backend/search_codebase_tool.py +377 -0
- kolega_code/agent/tool_backend/streaming_tool.py +47 -0
- kolega_code/agent/tool_backend/terminal_tool.py +643 -0
- kolega_code/agent/tool_backend/think_hard_tool.py +211 -0
- kolega_code/agent/tool_backend/web_fetch_tool.py +205 -0
- kolega_code/agent/tools.py +1704 -0
- kolega_code/agent/utils/commands.py +94 -0
- kolega_code/cli/__init__.py +1 -0
- kolega_code/cli/app.py +2756 -0
- kolega_code/cli/config.py +280 -0
- kolega_code/cli/connection.py +49 -0
- kolega_code/cli/file_index.py +147 -0
- kolega_code/cli/main.py +564 -0
- kolega_code/cli/mentions.py +155 -0
- kolega_code/cli/messages.py +89 -0
- kolega_code/cli/provider_registry.py +96 -0
- kolega_code/cli/session_store.py +207 -0
- kolega_code/cli/settings.py +87 -0
- kolega_code/cli/skills.py +409 -0
- kolega_code/cli/slash_commands.py +108 -0
- kolega_code/cli/tests/__init__.py +1 -0
- kolega_code/cli/tests/test_app.py +4251 -0
- kolega_code/cli/tests/test_cli_config.py +171 -0
- kolega_code/cli/tests/test_connection.py +26 -0
- kolega_code/cli/tests/test_file_index.py +103 -0
- kolega_code/cli/tests/test_main.py +455 -0
- kolega_code/cli/tests/test_mentions.py +108 -0
- kolega_code/cli/tests/test_session_store.py +67 -0
- kolega_code/cli/tests/test_settings.py +62 -0
- kolega_code/cli/tests/test_skills.py +157 -0
- kolega_code/cli/tests/test_slash_commands.py +88 -0
- kolega_code/cli/theme.py +180 -0
- kolega_code/config.py +154 -0
- kolega_code/events.py +202 -0
- kolega_code/llm/client.py +300 -0
- kolega_code/llm/exceptions.py +285 -0
- kolega_code/llm/instrumented_client.py +520 -0
- kolega_code/llm/models.py +1368 -0
- kolega_code/llm/providers/__init__.py +0 -0
- kolega_code/llm/providers/anthropic.py +387 -0
- kolega_code/llm/providers/base.py +71 -0
- kolega_code/llm/providers/google.py +157 -0
- kolega_code/llm/providers/models.py +37 -0
- kolega_code/llm/providers/openai.py +363 -0
- kolega_code/llm/ratelimit.py +40 -0
- kolega_code/llm/specs.py +67 -0
- kolega_code/llm/tool_execution_ids.py +18 -0
- kolega_code/models/__init__.py +9 -0
- kolega_code/models/sandbox_terminal_state.py +47 -0
- kolega_code/runtime.py +50 -0
- kolega_code/sandbox/README.md +200 -0
- kolega_code/sandbox/__init__.py +21 -0
- kolega_code/sandbox/async_filesystem.py +475 -0
- kolega_code/sandbox/base.py +297 -0
- kolega_code/sandbox/browser.py +25 -0
- kolega_code/sandbox/event_loop.py +43 -0
- kolega_code/sandbox/filesystem.py +341 -0
- kolega_code/sandbox/local.py +118 -0
- kolega_code/sandbox/serializer.py +175 -0
- kolega_code/sandbox/terminal.py +868 -0
- kolega_code/sandbox/utils.py +216 -0
- kolega_code/services/base.py +255 -0
- kolega_code/services/browser.py +444 -0
- kolega_code/services/file_system.py +749 -0
- kolega_code/services/html.py +221 -0
- kolega_code/services/terminal.py +903 -0
- kolega_code/tools/__init__.py +22 -0
- kolega_code/tools/core.py +33 -0
- kolega_code/tools/definitions.py +81 -0
- kolega_code/tools/registry.py +73 -0
- kolega_code-0.1.0.dist-info/METADATA +157 -0
- kolega_code-0.1.0.dist-info/RECORD +171 -0
- kolega_code-0.1.0.dist-info/WHEEL +4 -0
- kolega_code-0.1.0.dist-info/entry_points.txt +2 -0
- kolega_code-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
|
|
3
|
+
from bs4 import BeautifulSoup
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def extract_interactive_elements_from_html(html_content: str) -> List[Dict]:
|
|
7
|
+
"""
|
|
8
|
+
Extract interactive elements from HTML content with their associated text and selectors.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
html_content (str): HTML content as a string
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
List[Dict]: List of dictionaries containing element info with keys:
|
|
15
|
+
- 'element_type': Type of the element (button, link, input, etc.)
|
|
16
|
+
- 'selector': CSS selector to uniquely identify the element
|
|
17
|
+
- 'text': Associated text with the element
|
|
18
|
+
- 'attributes': Dictionary of element attributes
|
|
19
|
+
"""
|
|
20
|
+
soup = BeautifulSoup(html_content, "html.parser")
|
|
21
|
+
|
|
22
|
+
# Define interactive elements to look for
|
|
23
|
+
interactive_elements = [
|
|
24
|
+
# Links
|
|
25
|
+
"a",
|
|
26
|
+
# Form elements
|
|
27
|
+
"button",
|
|
28
|
+
"input",
|
|
29
|
+
"select",
|
|
30
|
+
"textarea",
|
|
31
|
+
"option",
|
|
32
|
+
# Interactive HTML5 elements
|
|
33
|
+
"details",
|
|
34
|
+
"summary",
|
|
35
|
+
"dialog",
|
|
36
|
+
# Elements that are often made interactive with JavaScript
|
|
37
|
+
'div[role="button"]',
|
|
38
|
+
'span[role="button"]',
|
|
39
|
+
"[aria-controls]",
|
|
40
|
+
"[onclick]",
|
|
41
|
+
"[onmouseover]",
|
|
42
|
+
"[onchange]",
|
|
43
|
+
'[contenteditable="true"]',
|
|
44
|
+
# Custom elements often used in frameworks
|
|
45
|
+
"[data-toggle]",
|
|
46
|
+
"[data-target]",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
results = []
|
|
50
|
+
|
|
51
|
+
# Process each type of interactive element
|
|
52
|
+
for selector in interactive_elements:
|
|
53
|
+
try:
|
|
54
|
+
if "[" in selector:
|
|
55
|
+
# Handle attribute-based selectors
|
|
56
|
+
tag_name, attr_part = selector.split("[", 1)
|
|
57
|
+
attr_part = attr_part.rstrip("]")
|
|
58
|
+
|
|
59
|
+
if "=" in attr_part:
|
|
60
|
+
# Attribute with specific value
|
|
61
|
+
attr_name, attr_value = attr_part.split("=", 1)
|
|
62
|
+
attr_value = attr_value.strip("\"'")
|
|
63
|
+
# Use find_all with attrs dict instead of select to avoid selector syntax issues
|
|
64
|
+
elements = soup.find_all(tag_name or True, attrs={attr_name: attr_value}) if tag_name else []
|
|
65
|
+
# Only try soup.select if we can't use the more reliable find_all method
|
|
66
|
+
if not elements and tag_name:
|
|
67
|
+
try:
|
|
68
|
+
elements = soup.select(selector)
|
|
69
|
+
except Exception:
|
|
70
|
+
# If select fails, continue with empty list
|
|
71
|
+
elements = []
|
|
72
|
+
else:
|
|
73
|
+
# Just the presence of an attribute
|
|
74
|
+
elements = soup.find_all(lambda tag: tag.has_attr(attr_part))
|
|
75
|
+
else:
|
|
76
|
+
# Simple tag selector
|
|
77
|
+
elements = soup.find_all(selector)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"Warning: Error processing selector '{selector}': {e}")
|
|
80
|
+
elements = []
|
|
81
|
+
|
|
82
|
+
for element in elements:
|
|
83
|
+
# Build a unique CSS selector for this element
|
|
84
|
+
element_selector = build_css_selector(element)
|
|
85
|
+
|
|
86
|
+
# Get the text associated with this element
|
|
87
|
+
element_text = get_associated_text(element)
|
|
88
|
+
|
|
89
|
+
# Get element type and attributes
|
|
90
|
+
element_type = element.name
|
|
91
|
+
attributes = {k: v for k, v in element.attrs.items()}
|
|
92
|
+
|
|
93
|
+
# Add to results
|
|
94
|
+
results.append(
|
|
95
|
+
{
|
|
96
|
+
"element_type": element_type,
|
|
97
|
+
"selector": element_selector,
|
|
98
|
+
"text": element_text,
|
|
99
|
+
"attributes": attributes,
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_associated_text(element) -> str:
|
|
107
|
+
"""
|
|
108
|
+
Get text associated with an element. Handles different element types appropriately.
|
|
109
|
+
"""
|
|
110
|
+
if element.name == "input":
|
|
111
|
+
# For input elements, use placeholder, value or label text
|
|
112
|
+
text = element.get("placeholder", "")
|
|
113
|
+
if not text and element.get("value") and element["type"] not in ["password", "hidden"]:
|
|
114
|
+
text = element["value"]
|
|
115
|
+
|
|
116
|
+
# Try to find associated label
|
|
117
|
+
element_id = element.get("id")
|
|
118
|
+
if element_id:
|
|
119
|
+
label = element.find_parent().find("label", attrs={"for": element_id})
|
|
120
|
+
if label:
|
|
121
|
+
return label.get_text(strip=True)
|
|
122
|
+
|
|
123
|
+
return text
|
|
124
|
+
|
|
125
|
+
elif element.name == "button":
|
|
126
|
+
# Get button text or value
|
|
127
|
+
return element.get_text(strip=True) or element.get("value", "")
|
|
128
|
+
|
|
129
|
+
elif element.name == "a":
|
|
130
|
+
# Get link text or title
|
|
131
|
+
return element.get_text(strip=True) or element.get("title", "")
|
|
132
|
+
|
|
133
|
+
elif element.name == "select":
|
|
134
|
+
# For select elements, include the text of the options
|
|
135
|
+
option_texts = [opt.get_text(strip=True) for opt in element.find_all("option")]
|
|
136
|
+
return ", ".join(filter(None, option_texts))
|
|
137
|
+
|
|
138
|
+
# Default: just return the text content
|
|
139
|
+
return element.get_text(strip=True)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def build_css_selector(element) -> str:
|
|
143
|
+
"""
|
|
144
|
+
Build a unique CSS selector for the given element.
|
|
145
|
+
Tries to create the most specific but concise selector.
|
|
146
|
+
Handles special characters and quotes in attribute values.
|
|
147
|
+
"""
|
|
148
|
+
# If element has ID, that's the simplest and most reliable selector
|
|
149
|
+
if element.get("id"):
|
|
150
|
+
return f"#{element['id']}"
|
|
151
|
+
|
|
152
|
+
# If element has classes, try to use them
|
|
153
|
+
if element.get("class"):
|
|
154
|
+
# Create individual class selectors and escape colons with backslashes
|
|
155
|
+
escaped_classes = []
|
|
156
|
+
for class_name in element["class"]:
|
|
157
|
+
# Escape colons in class names (for utility frameworks like Tailwind)
|
|
158
|
+
escaped_class = class_name.replace(":", "\\:")
|
|
159
|
+
escaped_classes.append(escaped_class)
|
|
160
|
+
|
|
161
|
+
class_selector = ".".join(escaped_classes)
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
if len(element.select(f".{class_selector}")) == 1:
|
|
165
|
+
return f".{class_selector}"
|
|
166
|
+
except Exception:
|
|
167
|
+
# If selector is invalid, fall back to other methods
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
# Try with tag name and attribute combinations
|
|
171
|
+
tag_name = element.name
|
|
172
|
+
attributes = element.attrs
|
|
173
|
+
|
|
174
|
+
for attr in ["name", "data-testid", "aria-label"]:
|
|
175
|
+
if attr in attributes:
|
|
176
|
+
attr_value = attributes[attr]
|
|
177
|
+
# Escape single quotes and handle special characters in attribute values
|
|
178
|
+
escaped_value = attr_value.replace("'", "\\'").replace('"', '\\"')
|
|
179
|
+
# Use double quotes to avoid issues with apostrophes in the content
|
|
180
|
+
selector = f'{tag_name}[{attr}="{escaped_value}"]'
|
|
181
|
+
try:
|
|
182
|
+
if len(element.find_parent().select(selector)) == 1:
|
|
183
|
+
return selector
|
|
184
|
+
except Exception:
|
|
185
|
+
# If the selector is invalid, try a simpler approach
|
|
186
|
+
continue
|
|
187
|
+
|
|
188
|
+
# Use nth-child as a last resort
|
|
189
|
+
parents = []
|
|
190
|
+
current = element
|
|
191
|
+
|
|
192
|
+
# Build the path up to 3 levels of parents
|
|
193
|
+
for _ in range(3):
|
|
194
|
+
siblings = current.find_parent().find_all(current.name, recursive=False) if current.parent else []
|
|
195
|
+
|
|
196
|
+
# Use 1-based index for nth-child
|
|
197
|
+
if siblings:
|
|
198
|
+
index = list(siblings).index(current) + 1
|
|
199
|
+
selector_part = f"{current.name}:nth-child({index})"
|
|
200
|
+
else:
|
|
201
|
+
selector_part = current.name
|
|
202
|
+
|
|
203
|
+
parents.append(selector_part)
|
|
204
|
+
current = current.parent
|
|
205
|
+
|
|
206
|
+
if current is None or current.name == "html":
|
|
207
|
+
break
|
|
208
|
+
|
|
209
|
+
# Construct the selector path
|
|
210
|
+
selector = " > ".join(reversed(parents))
|
|
211
|
+
|
|
212
|
+
# Validate the selector to make sure it's valid CSS
|
|
213
|
+
try:
|
|
214
|
+
# Test if the selector is valid by attempting to use it
|
|
215
|
+
soup = BeautifulSoup("<html><body></body></html>", "html.parser")
|
|
216
|
+
soup.select(selector)
|
|
217
|
+
return selector
|
|
218
|
+
except Exception:
|
|
219
|
+
# If the selector is invalid, return a very simple one
|
|
220
|
+
# This is a fallback that may not be unique but will be valid
|
|
221
|
+
return f"{element.name}"
|