camel-ai 0.2.75a6__py3-none-any.whl → 0.2.76a0__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.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (38) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +151 -37
  3. camel/configs/__init__.py +3 -0
  4. camel/configs/amd_config.py +70 -0
  5. camel/interpreters/__init__.py +2 -0
  6. camel/interpreters/microsandbox_interpreter.py +395 -0
  7. camel/models/__init__.py +2 -0
  8. camel/models/amd_model.py +101 -0
  9. camel/models/model_factory.py +2 -0
  10. camel/models/openai_model.py +0 -6
  11. camel/runtimes/daytona_runtime.py +11 -12
  12. camel/toolkits/__init__.py +5 -3
  13. camel/toolkits/code_execution.py +28 -1
  14. camel/toolkits/function_tool.py +6 -1
  15. camel/toolkits/hybrid_browser_toolkit/config_loader.py +8 -0
  16. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +12 -0
  17. camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +33 -14
  18. camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +135 -40
  19. camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +2 -0
  20. camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +43 -207
  21. camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
  22. camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +231 -0
  23. camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
  24. camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +39 -6
  25. camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +241 -56
  26. camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +5 -1
  27. camel/toolkits/{openai_image_toolkit.py → image_generation_toolkit.py} +98 -31
  28. camel/toolkits/mcp_toolkit.py +39 -14
  29. camel/toolkits/minimax_mcp_toolkit.py +195 -0
  30. camel/toolkits/terminal_toolkit.py +12 -2
  31. camel/toolkits/video_analysis_toolkit.py +16 -10
  32. camel/types/enums.py +11 -0
  33. camel/utils/commons.py +2 -0
  34. camel/utils/mcp.py +136 -2
  35. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a0.dist-info}/METADATA +5 -3
  36. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a0.dist-info}/RECORD +38 -31
  37. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a0.dist-info}/WHEEL +0 -0
  38. {camel_ai-0.2.75a6.dist-info → camel_ai-0.2.76a0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Parse snapshot text to extract parent-child relationships
3
+ */
4
+
5
+ export interface SnapshotNode {
6
+ ref: string;
7
+ type: string;
8
+ text?: string;
9
+ attributes: Record<string, string>;
10
+ children: string[]; // refs of child elements
11
+ parent?: string; // ref of parent element
12
+ }
13
+
14
+ export function parseSnapshotHierarchy(snapshotText: string): Map<string, SnapshotNode> {
15
+ const nodes = new Map<string, SnapshotNode>();
16
+ const lines = snapshotText.split('\n');
17
+
18
+ // Stack to track parent elements at each indentation level
19
+ const parentStack: { ref: string; indent: number }[] = [];
20
+
21
+ for (const line of lines) {
22
+ if (!line.trim()) continue;
23
+
24
+ // Calculate indentation
25
+ const indent = line.length - line.trimStart().length;
26
+
27
+ // Extract element info using regex
28
+ // Support both lines with : (have children) and without : (leaf nodes)
29
+ // Also support quoted lines like - 'button "text" [ref=...]'
30
+ // Also support escaped quotes in text
31
+ // Also support attributes before [ref=...]
32
+ // Extract type and optional label (before any [..] blocks)
33
+ const headerMatch = line.match(/^\s*(?:-\s*)?'?([a-z0-9_-]+)(?:\s+"((?:[^"\\]|\\.)*)")?/i);
34
+ if (!headerMatch) continue;
35
+ const [, typeRaw, label] = headerMatch;
36
+ const type = (typeRaw || 'unknown');
37
+
38
+ // Extract mandatory ref
39
+ const refMatch = line.match(/\[ref=([^\]]+)\]/i);
40
+ if (!refMatch) continue;
41
+ const ref = refMatch[1];
42
+
43
+ // Parse all bracketed attributes except the [ref=...] block
44
+ const attrs: Record<string, string> = {};
45
+ for (const block of line.matchAll(/\[([^\]]+)\]/g)) {
46
+ const content = block[1];
47
+ if (/^ref=/i.test(content)) continue;
48
+ const attrMatches = content.matchAll(/([a-z0-9_-]+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s\]]+)))?/gi);
49
+ for (const m of attrMatches) {
50
+ const key = m[1].toLowerCase();
51
+ const val = m[2] ?? m[3] ?? m[4] ?? 'true';
52
+ attrs[key] = val;
53
+ }
54
+ }
55
+
56
+ // Update parent stack based on indentation
57
+ while (parentStack.length > 0 && parentStack[parentStack.length - 1].indent >= indent) {
58
+ parentStack.pop();
59
+ }
60
+
61
+ // Create node
62
+ const node: SnapshotNode = {
63
+ ref,
64
+ type: type.toLowerCase(),
65
+ text: label || '',
66
+ attributes: attrs,
67
+ children: [],
68
+ parent: parentStack.length > 0 ? parentStack[parentStack.length - 1].ref : undefined
69
+ };
70
+
71
+ // Add to parent's children if has parent
72
+ if (node.parent && nodes.has(node.parent)) {
73
+ nodes.get(node.parent)!.children.push(ref);
74
+ }
75
+
76
+ // Add to nodes map
77
+ nodes.set(ref, node);
78
+
79
+ // Add to parent stack
80
+ parentStack.push({ ref, indent });
81
+ }
82
+
83
+ return nodes;
84
+ }
85
+
86
+ /**
87
+ * Find clickable elements that should be filtered based on DOM hierarchy
88
+ */
89
+ export function filterClickableByHierarchy(
90
+ snapshotText: string,
91
+ clickableElements: Set<string>
92
+ ): Set<string> {
93
+ const hierarchy = parseSnapshotHierarchy(snapshotText);
94
+ const filtered = new Set<string>(clickableElements);
95
+ const debugInfo: any[] = [];
96
+
97
+ // Debug clickable elements when enabled
98
+ const DEBUG_SNAPSHOT_PARSER = process.env.DEBUG_SNAPSHOT_PARSER === 'true';
99
+ if (DEBUG_SNAPSHOT_PARSER) {
100
+ clickableElements.forEach(ref => {
101
+ const node = hierarchy.get(ref);
102
+ if (node) {
103
+ console.log(`[Debug] ${ref} type: ${node.type}, parent: ${node.parent || 'none'}`);
104
+ } else {
105
+ console.log(`[Debug] ${ref} NOT FOUND in hierarchy!`);
106
+ }
107
+ });
108
+ }
109
+
110
+ // First pass: identify parent-child relationships where both are clickable
111
+ const parentChildPairs: Array<{parent: string, child: string, parentType: string, childType: string}> = [];
112
+
113
+ for (const childRef of clickableElements) {
114
+ const childNode = hierarchy.get(childRef);
115
+ if (!childNode || !childNode.parent) continue;
116
+
117
+ const parentRef = childNode.parent;
118
+ if (clickableElements.has(parentRef)) {
119
+ const parentNode = hierarchy.get(parentRef);
120
+ if (parentNode) {
121
+ parentChildPairs.push({
122
+ parent: parentRef,
123
+ child: childRef,
124
+ parentType: parentNode.type.toLowerCase(),
125
+ childType: childNode.type.toLowerCase()
126
+ });
127
+
128
+ // Debug specific pairs
129
+ if ((parentRef === 'e296' && childRef === 'e297') ||
130
+ (parentRef === 'e361' && childRef === 'e363') ||
131
+ (parentRef === 'e371' && childRef === 'e373') ||
132
+ (parentRef === 'e344' && childRef === 'e346') ||
133
+ (parentRef === 'e348' && childRef === 'e350')) {
134
+ console.log(`[Debug] Found pair: ${parentRef} (${parentNode.type}) -> ${childRef} (${childNode.type})`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ // Decide which elements to filter based on parent-child relationships
141
+ for (const pair of parentChildPairs) {
142
+ const { parent, child, parentType, childType } = pair;
143
+
144
+ // Rules for what to filter:
145
+ // 1. link > img: filter img (keep link)
146
+ // 2. button > generic: filter generic (keep button)
147
+ // 3. generic > button: filter generic (keep button)
148
+ // 4. link > generic: filter generic (keep link)
149
+ // 5. generic > generic: filter child (keep parent)
150
+ // 6. generic > unknown: filter child (keep parent)
151
+
152
+ if ((parentType === 'link' && childType === 'img') ||
153
+ (parentType === 'button' && childType === 'generic') ||
154
+ (parentType === 'link' && childType === 'generic') ||
155
+ (parentType === 'generic' && childType === 'generic') ||
156
+ (parentType === 'generic' && childType === 'unknown')) {
157
+ // Filter child
158
+ filtered.delete(child);
159
+ console.log(`[Hierarchy Filter] Filtered ${child} (${childType}) - keeping parent ${parent} (${parentType})`);
160
+ } else if (parentType === 'generic' && childType === 'button') {
161
+ // Special case: filter parent generic, keep child button
162
+ filtered.delete(parent);
163
+ console.log(`[Hierarchy Filter] Filtered ${parent} (${parentType}) - keeping child ${child} (${childType})`);
164
+ }
165
+ }
166
+
167
+ // Original logic for nested hierarchies (keep for deep nesting)
168
+ for (const childRef of clickableElements) {
169
+ if (!filtered.has(childRef)) continue; // Already filtered
170
+
171
+ const childNode = hierarchy.get(childRef);
172
+ if (!childNode || !childNode.parent) continue;
173
+
174
+ // Check if any ancestor is a propagating element
175
+ let currentParent: string | undefined = childNode.parent;
176
+ while (currentParent) {
177
+ if (clickableElements.has(currentParent) && filtered.has(currentParent)) {
178
+ const parentNode = hierarchy.get(currentParent);
179
+ if (parentNode) {
180
+ // Check if parent is a propagating element
181
+ const parentType = parentNode.type.toLowerCase();
182
+ const isPropagating = ['button', 'link', 'a'].includes(parentType) ||
183
+ (parentType === 'generic' && parentNode.attributes.cursor === 'pointer' && !parentNode.text);
184
+
185
+ if (isPropagating) {
186
+ // Filter child elements that should be contained within propagating parents
187
+ const childType = childNode.type.toLowerCase();
188
+
189
+ // Filter these types of children:
190
+ // 1. Generic elements with cursor=pointer
191
+ // 2. Images within links/buttons
192
+ // 3. Text elements (span, generic without specific role)
193
+ const shouldFilter =
194
+ (childType === 'generic' && childNode.attributes.cursor === 'pointer') ||
195
+ childType === 'img' ||
196
+ childType === 'span' ||
197
+ (childType === 'generic' && !childNode.attributes.role);
198
+
199
+ if (shouldFilter) {
200
+ filtered.delete(childRef);
201
+ console.log(`[Hierarchy Filter] Filtered ${childRef} (${childType}) contained in ${currentParent} (${parentType})`);
202
+ break;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ // Move up the hierarchy
208
+ const nextParent = hierarchy.get(currentParent);
209
+ currentParent = nextParent?.parent;
210
+ }
211
+ }
212
+
213
+ // Additional pass: if a generic parent contains only one button child, filter the parent
214
+ for (const ref of Array.from(filtered)) {
215
+ const node = hierarchy.get(ref);
216
+ if (!node || node.type.toLowerCase() !== 'generic') continue;
217
+
218
+ // Check if this generic has exactly one clickable child that's a button
219
+ const clickableChildren = node.children.filter(childRef =>
220
+ filtered.has(childRef) && hierarchy.get(childRef)?.type.toLowerCase() === 'button'
221
+ );
222
+
223
+ if (clickableChildren.length === 1) {
224
+ // This generic wraps a single button - filter it out
225
+ filtered.delete(ref);
226
+ console.log(`[Hierarchy Filter] Filtered ${ref} (generic wrapper around button ${clickableChildren[0]})`);
227
+ }
228
+ }
229
+
230
+ return filtered;
231
+ }