testchimp-runner-core 0.0.21 → 0.0.23

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 (146) hide show
  1. package/VISION_DIAGNOSTICS_IMPROVEMENTS.md +336 -0
  2. package/dist/credit-usage-service.d.ts +9 -0
  3. package/dist/credit-usage-service.d.ts.map +1 -1
  4. package/dist/credit-usage-service.js +20 -5
  5. package/dist/credit-usage-service.js.map +1 -1
  6. package/dist/execution-service.d.ts +7 -2
  7. package/dist/execution-service.d.ts.map +1 -1
  8. package/dist/execution-service.js +91 -36
  9. package/dist/execution-service.js.map +1 -1
  10. package/dist/index.d.ts +30 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +91 -26
  13. package/dist/index.js.map +1 -1
  14. package/dist/llm-facade.d.ts +64 -8
  15. package/dist/llm-facade.d.ts.map +1 -1
  16. package/dist/llm-facade.js +361 -109
  17. package/dist/llm-facade.js.map +1 -1
  18. package/dist/llm-provider.d.ts +39 -0
  19. package/dist/llm-provider.d.ts.map +1 -0
  20. package/dist/llm-provider.js +7 -0
  21. package/dist/llm-provider.js.map +1 -0
  22. package/dist/model-constants.d.ts +21 -0
  23. package/dist/model-constants.d.ts.map +1 -0
  24. package/dist/model-constants.js +24 -0
  25. package/dist/model-constants.js.map +1 -0
  26. package/dist/orchestrator/index.d.ts +8 -0
  27. package/dist/orchestrator/index.d.ts.map +1 -0
  28. package/dist/orchestrator/index.js +23 -0
  29. package/dist/orchestrator/index.js.map +1 -0
  30. package/dist/orchestrator/orchestrator-agent.d.ts +66 -0
  31. package/dist/orchestrator/orchestrator-agent.d.ts.map +1 -0
  32. package/dist/orchestrator/orchestrator-agent.js +855 -0
  33. package/dist/orchestrator/orchestrator-agent.js.map +1 -0
  34. package/dist/orchestrator/tool-registry.d.ts +74 -0
  35. package/dist/orchestrator/tool-registry.d.ts.map +1 -0
  36. package/dist/orchestrator/tool-registry.js +131 -0
  37. package/dist/orchestrator/tool-registry.js.map +1 -0
  38. package/dist/orchestrator/tools/check-page-ready.d.ts +13 -0
  39. package/dist/orchestrator/tools/check-page-ready.d.ts.map +1 -0
  40. package/dist/orchestrator/tools/check-page-ready.js +72 -0
  41. package/dist/orchestrator/tools/check-page-ready.js.map +1 -0
  42. package/dist/orchestrator/tools/extract-data.d.ts +13 -0
  43. package/dist/orchestrator/tools/extract-data.d.ts.map +1 -0
  44. package/dist/orchestrator/tools/extract-data.js +84 -0
  45. package/dist/orchestrator/tools/extract-data.js.map +1 -0
  46. package/dist/orchestrator/tools/index.d.ts +10 -0
  47. package/dist/orchestrator/tools/index.d.ts.map +1 -0
  48. package/dist/orchestrator/tools/index.js +18 -0
  49. package/dist/orchestrator/tools/index.js.map +1 -0
  50. package/dist/orchestrator/tools/inspect-page.d.ts +13 -0
  51. package/dist/orchestrator/tools/inspect-page.d.ts.map +1 -0
  52. package/dist/orchestrator/tools/inspect-page.js +39 -0
  53. package/dist/orchestrator/tools/inspect-page.js.map +1 -0
  54. package/dist/orchestrator/tools/recall-history.d.ts +13 -0
  55. package/dist/orchestrator/tools/recall-history.d.ts.map +1 -0
  56. package/dist/orchestrator/tools/recall-history.js +64 -0
  57. package/dist/orchestrator/tools/recall-history.js.map +1 -0
  58. package/dist/orchestrator/tools/take-screenshot.d.ts +15 -0
  59. package/dist/orchestrator/tools/take-screenshot.d.ts.map +1 -0
  60. package/dist/orchestrator/tools/take-screenshot.js +112 -0
  61. package/dist/orchestrator/tools/take-screenshot.js.map +1 -0
  62. package/dist/orchestrator/types.d.ts +133 -0
  63. package/dist/orchestrator/types.d.ts.map +1 -0
  64. package/dist/orchestrator/types.js +28 -0
  65. package/dist/orchestrator/types.js.map +1 -0
  66. package/dist/playwright-mcp-service.d.ts +9 -0
  67. package/dist/playwright-mcp-service.d.ts.map +1 -1
  68. package/dist/playwright-mcp-service.js +20 -5
  69. package/dist/playwright-mcp-service.js.map +1 -1
  70. package/dist/progress-reporter.d.ts +97 -0
  71. package/dist/progress-reporter.d.ts.map +1 -0
  72. package/dist/progress-reporter.js +18 -0
  73. package/dist/progress-reporter.js.map +1 -0
  74. package/dist/prompts.d.ts +24 -0
  75. package/dist/prompts.d.ts.map +1 -1
  76. package/dist/prompts.js +593 -68
  77. package/dist/prompts.js.map +1 -1
  78. package/dist/providers/backend-proxy-llm-provider.d.ts +25 -0
  79. package/dist/providers/backend-proxy-llm-provider.d.ts.map +1 -0
  80. package/dist/providers/backend-proxy-llm-provider.js +76 -0
  81. package/dist/providers/backend-proxy-llm-provider.js.map +1 -0
  82. package/dist/providers/local-llm-provider.d.ts +21 -0
  83. package/dist/providers/local-llm-provider.d.ts.map +1 -0
  84. package/dist/providers/local-llm-provider.js +35 -0
  85. package/dist/providers/local-llm-provider.js.map +1 -0
  86. package/dist/scenario-service.d.ts +27 -1
  87. package/dist/scenario-service.d.ts.map +1 -1
  88. package/dist/scenario-service.js +48 -12
  89. package/dist/scenario-service.js.map +1 -1
  90. package/dist/scenario-worker-class.d.ts +39 -2
  91. package/dist/scenario-worker-class.d.ts.map +1 -1
  92. package/dist/scenario-worker-class.js +614 -86
  93. package/dist/scenario-worker-class.js.map +1 -1
  94. package/dist/script-utils.d.ts +2 -0
  95. package/dist/script-utils.d.ts.map +1 -1
  96. package/dist/script-utils.js +44 -4
  97. package/dist/script-utils.js.map +1 -1
  98. package/dist/types.d.ts +11 -0
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js.map +1 -1
  101. package/dist/utils/browser-utils.d.ts +20 -1
  102. package/dist/utils/browser-utils.d.ts.map +1 -1
  103. package/dist/utils/browser-utils.js +102 -51
  104. package/dist/utils/browser-utils.js.map +1 -1
  105. package/dist/utils/page-info-utils.d.ts +23 -4
  106. package/dist/utils/page-info-utils.d.ts.map +1 -1
  107. package/dist/utils/page-info-utils.js +174 -43
  108. package/dist/utils/page-info-utils.js.map +1 -1
  109. package/package.json +1 -2
  110. package/plandocs/HUMAN_LIKE_IMPROVEMENTS.md +642 -0
  111. package/plandocs/MULTI_AGENT_ARCHITECTURE_REVIEW.md +844 -0
  112. package/plandocs/ORCHESTRATOR_MVP_SUMMARY.md +539 -0
  113. package/plandocs/PHASE1_ABSTRACTION_COMPLETE.md +241 -0
  114. package/plandocs/PHASE1_FINAL_STATUS.md +210 -0
  115. package/plandocs/PLANNING_SESSION_SUMMARY.md +372 -0
  116. package/plandocs/SCRIPT_CLEANUP_FEATURE.md +201 -0
  117. package/plandocs/SCRIPT_GENERATION_ARCHITECTURE.md +364 -0
  118. package/plandocs/SELECTOR_IMPROVEMENTS.md +139 -0
  119. package/src/credit-usage-service.ts +23 -5
  120. package/src/execution-service.ts +152 -42
  121. package/src/index.ts +169 -26
  122. package/src/llm-facade.ts +500 -126
  123. package/src/llm-provider.ts +43 -0
  124. package/src/model-constants.ts +23 -0
  125. package/src/orchestrator/index.ts +33 -0
  126. package/src/orchestrator/orchestrator-agent.ts +1037 -0
  127. package/src/orchestrator/tool-registry.ts +182 -0
  128. package/src/orchestrator/tools/check-page-ready.ts +75 -0
  129. package/src/orchestrator/tools/extract-data.ts +92 -0
  130. package/src/orchestrator/tools/index.ts +11 -0
  131. package/src/orchestrator/tools/inspect-page.ts +42 -0
  132. package/src/orchestrator/tools/recall-history.ts +72 -0
  133. package/src/orchestrator/tools/take-screenshot.ts +128 -0
  134. package/src/orchestrator/types.ts +200 -0
  135. package/src/playwright-mcp-service.ts +23 -5
  136. package/src/progress-reporter.ts +109 -0
  137. package/src/prompts.ts +606 -69
  138. package/src/providers/backend-proxy-llm-provider.ts +91 -0
  139. package/src/providers/local-llm-provider.ts +38 -0
  140. package/src/scenario-service.ts +83 -13
  141. package/src/scenario-worker-class.ts +740 -72
  142. package/src/script-utils.ts +50 -5
  143. package/src/types.ts +13 -1
  144. package/src/utils/browser-utils.ts +123 -51
  145. package/src/utils/page-info-utils.ts +210 -53
  146. package/testchimp-runner-core-0.0.22.tgz +0 -0
@@ -1,93 +1,250 @@
1
- // Page type will be dynamically imported
1
+ /**
2
+ * Enhanced Page Info Utilities
3
+ * Extracts ARIA tree, interactive elements with bounding boxes, and suggested selectors
4
+ */
5
+
6
+ export interface InteractiveElement {
7
+ tag: string;
8
+ id: string | null;
9
+ text: string;
10
+ type: string;
11
+ role: string;
12
+ ariaLabel: string;
13
+ placeholder: string;
14
+ bbox: {x: number; y: number; width: number; height: number};
15
+ selectors: string[];
16
+ }
2
17
 
3
18
  export interface PageInfo {
4
19
  url: string;
5
20
  title: string;
6
- elements: string;
7
- formFields: string;
8
- interactiveElements: string;
9
- pageStructure: string;
21
+ ariaSnapshot: any; // Raw ARIA tree for hierarchical structure
22
+ interactiveElements: InteractiveElement[]; // All interactive elements with position and selectors
23
+ formattedElements: string; // Human-readable summary for logging
10
24
  }
11
25
 
12
26
  export async function getEnhancedPageInfo(page: any): Promise<PageInfo>;
13
27
  export async function getEnhancedPageInfo(domSnapshot: { url: string; title: string; accessibilityTree: any }): Promise<PageInfo>;
14
28
  export async function getEnhancedPageInfo(input: any | { url: string; title: string; accessibilityTree: any }): Promise<PageInfo> {
15
29
  let domSnapshot: { url: string; title: string; accessibilityTree: any } = { url: 'Unknown', title: 'Unknown', accessibilityTree: null };
30
+ let interactiveElements: InteractiveElement[] = [];
31
+ let hasPageObject = false;
16
32
 
17
33
  try {
18
34
  if ('accessibility' in input) {
19
35
  // Input is a Page object
36
+ hasPageObject = true;
20
37
  const snapshot = await input.accessibility.snapshot();
21
38
  const url = input.url();
22
39
  const title = await input.title();
23
40
  domSnapshot = { url, title, accessibilityTree: snapshot };
41
+
42
+ // Extract ALL interactive elements with bounding boxes and selectors
43
+ try {
44
+ interactiveElements = await input.evaluate(() => {
45
+ const doc = (globalThis as any).document;
46
+ const elements: any[] = [];
47
+
48
+ // Get all interactive elements
49
+ const interactiveSelectors = [
50
+ 'button',
51
+ 'input',
52
+ 'textarea',
53
+ 'select',
54
+ 'a[href]',
55
+ '[role="button"]',
56
+ '[role="link"]',
57
+ '[role="textbox"]',
58
+ '[role="checkbox"]',
59
+ '[role="radio"]',
60
+ '[onclick]'
61
+ ];
62
+
63
+ const allInteractive = new Set<any>();
64
+ interactiveSelectors.forEach((selector: string) => {
65
+ doc.querySelectorAll(selector).forEach((el: any) => allInteractive.add(el));
66
+ });
67
+
68
+ allInteractive.forEach((el: any) => {
69
+ const rect = el.getBoundingClientRect();
70
+
71
+ // Skip invisible elements
72
+ if (rect.width === 0 || rect.height === 0) return;
73
+
74
+ const id = el.id || null;
75
+ const tag = el.tagName.toLowerCase();
76
+ const text = el.textContent?.trim().substring(0, 40) || '';
77
+ const type = el.type || '';
78
+ const role = el.getAttribute('role') || el.tagName.toLowerCase();
79
+ const ariaLabel = el.getAttribute('aria-label') || '';
80
+ const placeholder = el.placeholder || '';
81
+
82
+ // Build possible selectors - PRIORITIZE SEMANTIC SELECTORS (Playwright best practices)
83
+ const selectors: string[] = [];
84
+
85
+ // 1. BEST: getByLabel for form inputs with associated labels
86
+ if ((tag === 'input' || tag === 'textarea' || tag === 'select') && el.labels && el.labels.length > 0) {
87
+ const labelText = el.labels[0].textContent?.trim();
88
+ if (labelText && labelText.length > 0 && labelText.length < 50) {
89
+ selectors.push(`getByLabel('${labelText}')`);
90
+ }
91
+ }
92
+
93
+ // 2. BEST: getByRole with name (semantic and accessible)
94
+ if (text && text.length > 0 && text.length < 30) {
95
+ selectors.push(`getByRole('${role}', {name: '${text}'})`);
96
+ }
97
+
98
+ // 3. BEST: getByPlaceholder for inputs with placeholders
99
+ if (placeholder && placeholder.length > 0 && placeholder.length < 50) {
100
+ selectors.push(`getByPlaceholder('${placeholder}')`);
101
+ }
102
+
103
+ // 4. GOOD: getByText for elements with visible text (fallback for non-role elements)
104
+ if (text && text.length > 0 && text.length < 30 && !selectors.some(s => s.includes('getByRole'))) {
105
+ selectors.push(`getByText('${text}')`);
106
+ }
107
+
108
+ // 5. GOOD: data-testid attributes (stable, explicit)
109
+ const dataTestId = el.getAttribute('data-testid') || el.getAttribute('data-test-id') ||
110
+ el.getAttribute('data-id') || el.getAttribute('data-test');
111
+ if (dataTestId) selectors.push(`getByTestId('${dataTestId}')`);
112
+
113
+ // 6. LAST RESORT: ID selector (only if stable - avoid auto-generated IDs with unicode)
114
+ // Skip auto-generated Ant Design IDs like «r3»-form-item or rc_select_xxx
115
+ if (id && !id.includes('«') && !id.match(/^(rc_|:r[0-9]+:|__)/)) {
116
+ selectors.push(`#${id}`);
117
+ }
118
+
119
+ elements.push({
120
+ tag,
121
+ id,
122
+ text,
123
+ type,
124
+ role,
125
+ ariaLabel,
126
+ placeholder,
127
+ bbox: {
128
+ x: Math.round(rect.x),
129
+ y: Math.round(rect.y),
130
+ width: Math.round(rect.width),
131
+ height: Math.round(rect.height)
132
+ },
133
+ selectors
134
+ });
135
+ });
136
+
137
+ return elements;
138
+ });
139
+ } catch (evalError: any) {
140
+ // Error extracting interactive elements - continue with empty array
141
+ console.error('[getEnhancedPageInfo] Failed to extract interactive elements:', evalError.message);
142
+ interactiveElements = [];
143
+ }
24
144
  } else {
25
145
  // Input is already a domSnapshot
26
146
  domSnapshot = input;
27
147
  }
28
148
 
29
- // Extract key information from accessibility tree
30
- const elements: string[] = [];
31
- const formFields: string[] = [];
32
- const interactiveElements: string[] = [];
33
- const pageStructure: string[] = [];
34
-
35
- const extractElements = (node: any, depth = 0) => {
36
- if (depth > 4) return; // Limit depth to avoid overwhelming output
149
+ // Log extraction results for debugging
150
+ if (hasPageObject) {
151
+ console.log(`[getEnhancedPageInfo] Extracted ${interactiveElements.length} interactive elements from ${domSnapshot.url}`);
152
+ }
153
+
154
+ // Create smart summary prioritizing important elements over repetitive lists
155
+ let formattedElements = '';
156
+
157
+ if (interactiveElements.length > 0) {
158
+ // Prioritize: forms/buttons > unique elements > list items
159
+ const prioritized: InteractiveElement[] = [];
160
+ const listItems: InteractiveElement[] = [];
37
161
 
38
- if (node && typeof node === 'object') {
39
- if (node.role) {
40
- const elementInfo = `${node.role}${node.name ? `: ${node.name}` : ''}`;
41
- elements.push(elementInfo);
42
-
43
- // Categorize elements
44
- if (['textbox', 'button', 'link', 'checkbox', 'radio', 'combobox', 'slider'].includes(node.role)) {
45
- interactiveElements.push(elementInfo);
46
- }
47
-
48
- if (['textbox', 'checkbox', 'radio', 'combobox', 'slider'].includes(node.role)) {
49
- formFields.push(elementInfo);
162
+ // Group elements
163
+ for (const el of interactiveElements) {
164
+ // High priority: forms, buttons, unique interactive elements
165
+ if (['input', 'textarea', 'select', 'button'].includes(el.tag) ||
166
+ (el.tag === 'a' && el.text.length > 0 && el.text.length < 50)) {
167
+ prioritized.push(el);
168
+ } else {
169
+ listItems.push(el);
170
+ }
171
+ }
172
+
173
+ // Take top 25 prioritized
174
+ const selectedElements = prioritized.slice(0, 25);
175
+
176
+ // Add sample of list items if space remains (show diversity, not just first N)
177
+ if (selectedElements.length < 30 && listItems.length > 0) {
178
+ const step = Math.max(1, Math.floor(listItems.length / 5)); // Sample 5 from list
179
+ for (let i = 0; i < Math.min(5, listItems.length); i++) {
180
+ selectedElements.push(listItems[i * step]);
181
+ }
182
+ }
183
+
184
+ formattedElements = selectedElements.map((e, i) => {
185
+ const idInfo = e.id ? `#${e.id}` : 'NO-ID';
186
+ const typeInfo = e.type ? ` type="${e.type}"` : '';
187
+ const placeholderInfo = e.placeholder ? ` placeholder="${e.placeholder}"` : '';
188
+
189
+ // Show BEST selector first, with alternatives
190
+ let selectorsInfo: string;
191
+ if (e.selectors && e.selectors.length > 0) {
192
+ selectorsInfo = e.selectors[0]; // Best option
193
+ if (e.selectors.length > 1) {
194
+ selectorsInfo += ` (or: ${e.selectors.slice(1, 3).join(', ')})`; // Show up to 2 alternatives
50
195
  }
51
-
52
- if (['main', 'navigation', 'banner', 'contentinfo', 'complementary', 'search'].includes(node.role)) {
53
- pageStructure.push(elementInfo);
196
+ } else {
197
+ selectorsInfo = 'No reliable selector available';
198
+ }
199
+
200
+ return `${i + 1}. [${e.bbox.x},${e.bbox.y} ${e.bbox.width}x${e.bbox.height}] <${e.tag}> ${idInfo}${typeInfo}${placeholderInfo} "${e.text}"
201
+ → ${selectorsInfo}`;
202
+ }).join('\n');
203
+
204
+ // Show stats for omitted elements
205
+ const omitted = interactiveElements.length - selectedElements.length;
206
+ if (omitted > 0) {
207
+ formattedElements += `\n\n... (+${omitted} more elements)`;
208
+
209
+ // Show pattern summary for lists/tables
210
+ const linkCount = interactiveElements.filter(e => e.tag === 'a').length;
211
+ const listItemPatterns: Record<string, number> = {};
212
+
213
+ for (const el of interactiveElements) {
214
+ if (el.tag === 'a' || el.tag === 'li' || el.tag === 'div') {
215
+ const pattern = `${el.tag}${el.role ? `[${el.role}]` : ''}`;
216
+ listItemPatterns[pattern] = (listItemPatterns[pattern] || 0) + 1;
54
217
  }
55
218
  }
56
-
57
- if (node.children) {
58
- node.children.forEach((child: any) => extractElements(child, depth + 1));
219
+
220
+ if (Object.keys(listItemPatterns).length > 0) {
221
+ formattedElements += `\nPattern summary: `;
222
+ formattedElements += Object.entries(listItemPatterns)
223
+ .filter(([_, count]) => count > 5)
224
+ .map(([pattern, count]) => `${count}x ${pattern}`)
225
+ .join(', ');
59
226
  }
60
227
  }
61
- };
62
-
63
- extractElements(domSnapshot.accessibilityTree);
64
-
65
- // Create a more focused summary
66
- const getElementSummary = (elementList: string[], maxItems: number, category: string) => {
67
- if (elementList.length === 0) return `No ${category} found`;
68
- const limited = elementList.slice(0, maxItems);
69
- const remaining = elementList.length - maxItems;
70
- const summary = limited.join(', ');
71
- return remaining > 0 ? `${summary} (+${remaining} more)` : summary;
72
- };
228
+ } else {
229
+ formattedElements = 'No interactive elements found (page may not be loaded or extraction failed)';
230
+ }
73
231
 
74
232
  return {
75
233
  url: domSnapshot.url,
76
234
  title: domSnapshot.title,
77
- elements: getElementSummary(elements, 15, 'elements'),
78
- formFields: getElementSummary(formFields, 8, 'form fields'),
79
- interactiveElements: getElementSummary(interactiveElements, 12, 'interactive elements'),
80
- pageStructure: getElementSummary(pageStructure, 6, 'page sections')
235
+ ariaSnapshot: domSnapshot.accessibilityTree,
236
+ interactiveElements,
237
+ formattedElements
81
238
  };
82
- } catch (error) {
83
- console.error('Error extracting page info:', error);
239
+ } catch (error: any) {
240
+ // Error extracting page info - return defaults
241
+ console.error('[getEnhancedPageInfo] Top-level error:', error.message);
84
242
  return {
85
243
  url: domSnapshot?.url || 'Unknown',
86
244
  title: 'Unknown',
87
- elements: 'Unable to extract',
88
- formFields: 'Unable to extract',
89
- interactiveElements: 'Unable to extract',
90
- pageStructure: 'Unable to extract'
245
+ ariaSnapshot: null,
246
+ interactiveElements: [],
247
+ formattedElements: `Unable to extract: ${error.message}`
91
248
  };
92
249
  }
93
250
  }
Binary file