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.
Files changed (171) hide show
  1. kolega_code/__init__.py +151 -0
  2. kolega_code/agent/__init__.py +42 -0
  3. kolega_code/agent/baseagent.py +998 -0
  4. kolega_code/agent/browseragent.py +123 -0
  5. kolega_code/agent/coder.py +157 -0
  6. kolega_code/agent/common.py +41 -0
  7. kolega_code/agent/compression.py +81 -0
  8. kolega_code/agent/context.py +112 -0
  9. kolega_code/agent/conversation.py +408 -0
  10. kolega_code/agent/generalagent.py +146 -0
  11. kolega_code/agent/investigationagent.py +123 -0
  12. kolega_code/agent/planningagent.py +187 -0
  13. kolega_code/agent/prompt_provider.py +196 -0
  14. kolega_code/agent/prompt_templates/agents/browser.j2 +102 -0
  15. kolega_code/agent/prompt_templates/agents/coder_cli_mode.j2 +127 -0
  16. kolega_code/agent/prompt_templates/agents/general.j2 +68 -0
  17. kolega_code/agent/prompt_templates/agents/investigation.j2 +72 -0
  18. kolega_code/agent/prompt_templates/common/frontend_guidance.md +36 -0
  19. kolega_code/agent/prompt_templates/common/kolega_md_instructions.md +14 -0
  20. kolega_code/agent/prompt_templates/environment_variables/workspace_env_vars.md +11 -0
  21. kolega_code/agent/prompt_templates/template_guidance/expo-template.md +379 -0
  22. kolega_code/agent/prompt_templates/template_guidance/html-website-template.md +3 -0
  23. kolega_code/agent/prompt_templates/template_guidance/mern-stack-template.md +3 -0
  24. kolega_code/agent/prompt_templates/template_guidance/react-vite-shadcdn-template.md +182 -0
  25. kolega_code/agent/prompts.py +192 -0
  26. kolega_code/agent/tests/__init__.py +0 -0
  27. kolega_code/agent/tests/llm/__init__.py +0 -0
  28. kolega_code/agent/tests/llm/test_anthropic_token_counting.py +633 -0
  29. kolega_code/agent/tests/llm/test_billing_openai_cache.py +74 -0
  30. kolega_code/agent/tests/llm/test_client.py +773 -0
  31. kolega_code/agent/tests/llm/test_dashscope_mapping.py +32 -0
  32. kolega_code/agent/tests/llm/test_error_boundary.py +322 -0
  33. kolega_code/agent/tests/llm/test_exceptions.py +249 -0
  34. kolega_code/agent/tests/llm/test_instrumented_client.py +536 -0
  35. kolega_code/agent/tests/llm/test_instrumented_client_integration.py +547 -0
  36. kolega_code/agent/tests/llm/test_langfuse_normalization.py +39 -0
  37. kolega_code/agent/tests/llm/test_model_specs.py +17 -0
  38. kolega_code/agent/tests/llm/test_openai_cached_tokens.py +58 -0
  39. kolega_code/agent/tests/llm/test_openai_cached_tokens_stream.py +74 -0
  40. kolega_code/agent/tests/llm/test_openai_message_conversion.py +30 -0
  41. kolega_code/agent/tests/llm/test_openai_token_counting.py +687 -0
  42. kolega_code/agent/tests/llm/test_tool_execution_ids.py +193 -0
  43. kolega_code/agent/tests/services/__init__.py +1 -0
  44. kolega_code/agent/tests/services/test_browser.py +447 -0
  45. kolega_code/agent/tests/services/test_browser_parity.py +353 -0
  46. kolega_code/agent/tests/services/test_file_system.py +699 -0
  47. kolega_code/agent/tests/services/test_sandbox_terminal_input.py +98 -0
  48. kolega_code/agent/tests/services/test_terminal.py +154 -0
  49. kolega_code/agent/tests/services/test_terminal_command_tracking.py +385 -0
  50. kolega_code/agent/tests/services/test_terminal_state_serializer.py +262 -0
  51. kolega_code/agent/tests/test_agent_tools_inventory.py +267 -0
  52. kolega_code/agent/tests/test_base_agent.py +1942 -0
  53. kolega_code/agent/tests/test_coder_attachments.py +330 -0
  54. kolega_code/agent/tests/test_coder_prompt_extensions.py +61 -0
  55. kolega_code/agent/tests/test_commands.py +179 -0
  56. kolega_code/agent/tests/test_duplicate_tool_results.py +556 -0
  57. kolega_code/agent/tests/test_empty_message_handling.py +48 -0
  58. kolega_code/agent/tests/test_general_agent.py +242 -0
  59. kolega_code/agent/tests/test_html.py +320 -0
  60. kolega_code/agent/tests/test_parallel_tool_calls.py +291 -0
  61. kolega_code/agent/tests/test_planning_agent.py +227 -0
  62. kolega_code/agent/tests/test_prompt_provider.py +271 -0
  63. kolega_code/agent/tests/test_tool_registry.py +102 -0
  64. kolega_code/agent/tests/test_tools.py +549 -0
  65. kolega_code/agent/tests/tool_backend/__init__.py +0 -0
  66. kolega_code/agent/tests/tool_backend/test_agent_tool.py +356 -0
  67. kolega_code/agent/tests/tool_backend/test_base_tool.py +147 -0
  68. kolega_code/agent/tests/tool_backend/test_browser_tool.py +335 -0
  69. kolega_code/agent/tests/tool_backend/test_build_tool.py +93 -0
  70. kolega_code/agent/tests/tool_backend/test_create_file_tool.py +115 -0
  71. kolega_code/agent/tests/tool_backend/test_glob_tool.py +196 -0
  72. kolega_code/agent/tests/tool_backend/test_glob_tool_sandbox_parity.py +230 -0
  73. kolega_code/agent/tests/tool_backend/test_list_directory_tool.py +292 -0
  74. kolega_code/agent/tests/tool_backend/test_read_file_tool.py +173 -0
  75. kolega_code/agent/tests/tool_backend/test_replace_entire_file_tool.py +115 -0
  76. kolega_code/agent/tests/tool_backend/test_replace_lines_tool.py +141 -0
  77. kolega_code/agent/tests/tool_backend/test_search_and_replace_tool.py +174 -0
  78. kolega_code/agent/tests/tool_backend/test_search_codebase_tool.py +228 -0
  79. kolega_code/agent/tests/tool_backend/test_terminal_tool.py +482 -0
  80. kolega_code/agent/tests/tool_backend/test_think_hard_integration.py +189 -0
  81. kolega_code/agent/tests/tool_backend/test_think_hard_streaming.py +445 -0
  82. kolega_code/agent/tests/tool_backend/test_web_fetch_tool.py +194 -0
  83. kolega_code/agent/tool_backend/agent_tool.py +414 -0
  84. kolega_code/agent/tool_backend/apply_edit_tool.py +98 -0
  85. kolega_code/agent/tool_backend/apply_patch_tool.py +514 -0
  86. kolega_code/agent/tool_backend/base_tool.py +217 -0
  87. kolega_code/agent/tool_backend/browser_tool.py +271 -0
  88. kolega_code/agent/tool_backend/build_tool.py +93 -0
  89. kolega_code/agent/tool_backend/create_file_tool.py +52 -0
  90. kolega_code/agent/tool_backend/glob_tool.py +323 -0
  91. kolega_code/agent/tool_backend/list_directory_tool.py +300 -0
  92. kolega_code/agent/tool_backend/memory_tool.py +79 -0
  93. kolega_code/agent/tool_backend/read_file_tool.py +119 -0
  94. kolega_code/agent/tool_backend/replace_entire_file_tool.py +40 -0
  95. kolega_code/agent/tool_backend/replace_lines_tool.py +97 -0
  96. kolega_code/agent/tool_backend/search_and_replace_tool.py +146 -0
  97. kolega_code/agent/tool_backend/search_codebase_tool.py +377 -0
  98. kolega_code/agent/tool_backend/streaming_tool.py +47 -0
  99. kolega_code/agent/tool_backend/terminal_tool.py +643 -0
  100. kolega_code/agent/tool_backend/think_hard_tool.py +211 -0
  101. kolega_code/agent/tool_backend/web_fetch_tool.py +205 -0
  102. kolega_code/agent/tools.py +1704 -0
  103. kolega_code/agent/utils/commands.py +94 -0
  104. kolega_code/cli/__init__.py +1 -0
  105. kolega_code/cli/app.py +2756 -0
  106. kolega_code/cli/config.py +280 -0
  107. kolega_code/cli/connection.py +49 -0
  108. kolega_code/cli/file_index.py +147 -0
  109. kolega_code/cli/main.py +564 -0
  110. kolega_code/cli/mentions.py +155 -0
  111. kolega_code/cli/messages.py +89 -0
  112. kolega_code/cli/provider_registry.py +96 -0
  113. kolega_code/cli/session_store.py +207 -0
  114. kolega_code/cli/settings.py +87 -0
  115. kolega_code/cli/skills.py +409 -0
  116. kolega_code/cli/slash_commands.py +108 -0
  117. kolega_code/cli/tests/__init__.py +1 -0
  118. kolega_code/cli/tests/test_app.py +4251 -0
  119. kolega_code/cli/tests/test_cli_config.py +171 -0
  120. kolega_code/cli/tests/test_connection.py +26 -0
  121. kolega_code/cli/tests/test_file_index.py +103 -0
  122. kolega_code/cli/tests/test_main.py +455 -0
  123. kolega_code/cli/tests/test_mentions.py +108 -0
  124. kolega_code/cli/tests/test_session_store.py +67 -0
  125. kolega_code/cli/tests/test_settings.py +62 -0
  126. kolega_code/cli/tests/test_skills.py +157 -0
  127. kolega_code/cli/tests/test_slash_commands.py +88 -0
  128. kolega_code/cli/theme.py +180 -0
  129. kolega_code/config.py +154 -0
  130. kolega_code/events.py +202 -0
  131. kolega_code/llm/client.py +300 -0
  132. kolega_code/llm/exceptions.py +285 -0
  133. kolega_code/llm/instrumented_client.py +520 -0
  134. kolega_code/llm/models.py +1368 -0
  135. kolega_code/llm/providers/__init__.py +0 -0
  136. kolega_code/llm/providers/anthropic.py +387 -0
  137. kolega_code/llm/providers/base.py +71 -0
  138. kolega_code/llm/providers/google.py +157 -0
  139. kolega_code/llm/providers/models.py +37 -0
  140. kolega_code/llm/providers/openai.py +363 -0
  141. kolega_code/llm/ratelimit.py +40 -0
  142. kolega_code/llm/specs.py +67 -0
  143. kolega_code/llm/tool_execution_ids.py +18 -0
  144. kolega_code/models/__init__.py +9 -0
  145. kolega_code/models/sandbox_terminal_state.py +47 -0
  146. kolega_code/runtime.py +50 -0
  147. kolega_code/sandbox/README.md +200 -0
  148. kolega_code/sandbox/__init__.py +21 -0
  149. kolega_code/sandbox/async_filesystem.py +475 -0
  150. kolega_code/sandbox/base.py +297 -0
  151. kolega_code/sandbox/browser.py +25 -0
  152. kolega_code/sandbox/event_loop.py +43 -0
  153. kolega_code/sandbox/filesystem.py +341 -0
  154. kolega_code/sandbox/local.py +118 -0
  155. kolega_code/sandbox/serializer.py +175 -0
  156. kolega_code/sandbox/terminal.py +868 -0
  157. kolega_code/sandbox/utils.py +216 -0
  158. kolega_code/services/base.py +255 -0
  159. kolega_code/services/browser.py +444 -0
  160. kolega_code/services/file_system.py +749 -0
  161. kolega_code/services/html.py +221 -0
  162. kolega_code/services/terminal.py +903 -0
  163. kolega_code/tools/__init__.py +22 -0
  164. kolega_code/tools/core.py +33 -0
  165. kolega_code/tools/definitions.py +81 -0
  166. kolega_code/tools/registry.py +73 -0
  167. kolega_code-0.1.0.dist-info/METADATA +157 -0
  168. kolega_code-0.1.0.dist-info/RECORD +171 -0
  169. kolega_code-0.1.0.dist-info/WHEEL +4 -0
  170. kolega_code-0.1.0.dist-info/entry_points.txt +2 -0
  171. 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}"