sentienceapi 0.92.2__py3-none-any.whl → 0.98.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.

Potentially problematic release.


This version of sentienceapi might be problematic. Click here for more details.

Files changed (64) hide show
  1. sentience/__init__.py +107 -2
  2. sentience/_extension_loader.py +156 -1
  3. sentience/action_executor.py +2 -0
  4. sentience/actions.py +354 -9
  5. sentience/agent.py +4 -0
  6. sentience/agent_runtime.py +840 -0
  7. sentience/asserts/__init__.py +70 -0
  8. sentience/asserts/expect.py +621 -0
  9. sentience/asserts/query.py +383 -0
  10. sentience/async_api.py +8 -1
  11. sentience/backends/__init__.py +137 -0
  12. sentience/backends/actions.py +372 -0
  13. sentience/backends/browser_use_adapter.py +241 -0
  14. sentience/backends/cdp_backend.py +393 -0
  15. sentience/backends/exceptions.py +211 -0
  16. sentience/backends/playwright_backend.py +194 -0
  17. sentience/backends/protocol.py +216 -0
  18. sentience/backends/sentience_context.py +469 -0
  19. sentience/backends/snapshot.py +483 -0
  20. sentience/browser.py +230 -74
  21. sentience/canonicalization.py +207 -0
  22. sentience/cloud_tracing.py +65 -24
  23. sentience/constants.py +6 -0
  24. sentience/cursor_policy.py +142 -0
  25. sentience/extension/content.js +35 -0
  26. sentience/extension/injected_api.js +310 -15
  27. sentience/extension/manifest.json +1 -1
  28. sentience/extension/pkg/sentience_core.d.ts +22 -22
  29. sentience/extension/pkg/sentience_core.js +192 -144
  30. sentience/extension/pkg/sentience_core_bg.wasm +0 -0
  31. sentience/extension/release.json +29 -29
  32. sentience/failure_artifacts.py +241 -0
  33. sentience/integrations/__init__.py +6 -0
  34. sentience/integrations/langchain/__init__.py +12 -0
  35. sentience/integrations/langchain/context.py +18 -0
  36. sentience/integrations/langchain/core.py +326 -0
  37. sentience/integrations/langchain/tools.py +180 -0
  38. sentience/integrations/models.py +46 -0
  39. sentience/integrations/pydanticai/__init__.py +15 -0
  40. sentience/integrations/pydanticai/deps.py +20 -0
  41. sentience/integrations/pydanticai/toolset.py +468 -0
  42. sentience/llm_provider.py +695 -18
  43. sentience/models.py +536 -3
  44. sentience/ordinal.py +280 -0
  45. sentience/query.py +66 -4
  46. sentience/schemas/trace_v1.json +27 -1
  47. sentience/snapshot.py +384 -93
  48. sentience/snapshot_diff.py +39 -54
  49. sentience/text_search.py +1 -0
  50. sentience/trace_event_builder.py +20 -1
  51. sentience/trace_indexing/indexer.py +3 -49
  52. sentience/tracer_factory.py +1 -3
  53. sentience/verification.py +618 -0
  54. sentience/visual_agent.py +3 -1
  55. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/METADATA +198 -40
  56. sentienceapi-0.98.0.dist-info/RECORD +92 -0
  57. sentience/utils.py +0 -296
  58. sentienceapi-0.92.2.dist-info/RECORD +0 -65
  59. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/WHEEL +0 -0
  60. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/entry_points.txt +0 -0
  61. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE +0 -0
  62. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE-APACHE +0 -0
  63. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/licenses/LICENSE-MIT +0 -0
  64. {sentienceapi-0.92.2.dist-info → sentienceapi-0.98.0.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,165 @@
10
10
  }
11
11
  return elements;
12
12
  }
13
+ const CAPTCHA_TEXT_KEYWORDS = [ "verify you are human", "captcha", "human verification", "unusual traffic", "are you a robot", "security check", "prove you are human", "bot detection", "automated access" ], CAPTCHA_URL_HINTS = [ "captcha", "challenge", "verify" ], CAPTCHA_IFRAME_HINTS = {
14
+ recaptcha: [ "recaptcha", "google.com/recaptcha" ],
15
+ hcaptcha: [ "hcaptcha.com" ],
16
+ turnstile: [ "challenges.cloudflare.com", "turnstile" ],
17
+ arkose: [ "arkoselabs.com", "funcaptcha.com", "client-api.arkoselabs.com" ],
18
+ awswaf: [ "amazonaws.com/captcha", "awswaf.com" ]
19
+ }, CAPTCHA_SCRIPT_HINTS = {
20
+ recaptcha: [ "recaptcha" ],
21
+ hcaptcha: [ "hcaptcha" ],
22
+ turnstile: [ "turnstile", "challenges.cloudflare.com" ],
23
+ arkose: [ "arkoselabs", "funcaptcha" ],
24
+ awswaf: [ "captcha.awswaf", "awswaf-captcha" ]
25
+ }, CAPTCHA_CONTAINER_SELECTORS = [ {
26
+ selector: ".g-recaptcha",
27
+ provider: "recaptcha"
28
+ }, {
29
+ selector: "#g-recaptcha",
30
+ provider: "recaptcha"
31
+ }, {
32
+ selector: "[data-sitekey]",
33
+ provider: "unknown"
34
+ }, {
35
+ selector: 'iframe[title*="recaptcha" i]',
36
+ provider: "recaptcha"
37
+ }, {
38
+ selector: ".h-captcha",
39
+ provider: "hcaptcha"
40
+ }, {
41
+ selector: "#h-captcha",
42
+ provider: "hcaptcha"
43
+ }, {
44
+ selector: 'iframe[title*="hcaptcha" i]',
45
+ provider: "hcaptcha"
46
+ }, {
47
+ selector: ".cf-turnstile",
48
+ provider: "turnstile"
49
+ }, {
50
+ selector: "[data-cf-turnstile-sitekey]",
51
+ provider: "turnstile"
52
+ }, {
53
+ selector: 'iframe[src*="challenges.cloudflare.com"]',
54
+ provider: "turnstile"
55
+ }, {
56
+ selector: "#FunCaptcha",
57
+ provider: "arkose"
58
+ }, {
59
+ selector: ".funcaptcha",
60
+ provider: "arkose"
61
+ }, {
62
+ selector: "[data-arkose-public-key]",
63
+ provider: "arkose"
64
+ }, {
65
+ selector: 'iframe[src*="arkoselabs"]',
66
+ provider: "arkose"
67
+ }, {
68
+ selector: "#captcha-container",
69
+ provider: "awswaf"
70
+ }, {
71
+ selector: "[data-awswaf-captcha]",
72
+ provider: "awswaf"
73
+ }, {
74
+ selector: 'iframe[title*="captcha" i]',
75
+ provider: "unknown"
76
+ } ];
77
+ function addEvidence(list, value) {
78
+ value && (list.length >= 5 || list.push(value));
79
+ }
80
+ function truncateText(text, maxLen) {
81
+ return text ? text.length <= maxLen ? text : text.slice(0, maxLen) : "";
82
+ }
83
+ function matchHints(value, hints) {
84
+ const lower = String(value || "").toLowerCase();
85
+ return !!lower && hints.some(hint => lower.includes(hint));
86
+ }
87
+ function detectCaptcha() {
88
+ const evidence = {
89
+ text_hits: [],
90
+ selector_hits: [],
91
+ iframe_src_hits: [],
92
+ url_hits: []
93
+ };
94
+ let hasIframeHit = !1, hasContainerHit = !1, hasScriptHit = !1, hasKeywordHit = !1, hasUrlHit = !1;
95
+ const providerSignals = {
96
+ recaptcha: 0,
97
+ hcaptcha: 0,
98
+ turnstile: 0,
99
+ arkose: 0,
100
+ awswaf: 0
101
+ };
102
+ try {
103
+ const iframes = document.querySelectorAll("iframe");
104
+ for (const iframe of iframes) {
105
+ const src = iframe.getAttribute("src") || "", title = iframe.getAttribute("title") || "";
106
+ if (src) for (const [provider, hints] of Object.entries(CAPTCHA_IFRAME_HINTS)) matchHints(src, hints) && (hasIframeHit = !0,
107
+ providerSignals[provider] += 1, addEvidence(evidence.iframe_src_hits, truncateText(src, 120)));
108
+ if (title && matchHints(title, [ "captcha", "recaptcha" ]) && (hasContainerHit = !0,
109
+ addEvidence(evidence.selector_hits, 'iframe[title*="captcha"]')), evidence.iframe_src_hits.length >= 5) break;
110
+ }
111
+ } catch (e) {}
112
+ try {
113
+ const scripts = document.querySelectorAll("script[src]");
114
+ for (const script of scripts) {
115
+ const src = script.getAttribute("src") || "";
116
+ if (src) {
117
+ for (const [provider, hints] of Object.entries(CAPTCHA_SCRIPT_HINTS)) matchHints(src, hints) && (hasScriptHit = !0,
118
+ providerSignals[provider] += 1, addEvidence(evidence.selector_hits, `script[src*="${hints[0]}"]`));
119
+ if (evidence.selector_hits.length >= 5) break;
120
+ }
121
+ }
122
+ } catch (e) {}
123
+ for (const {selector: selector, provider: provider} of CAPTCHA_CONTAINER_SELECTORS) try {
124
+ document.querySelector(selector) && (hasContainerHit = !0, addEvidence(evidence.selector_hits, selector),
125
+ "unknown" !== provider && (providerSignals[provider] += 1));
126
+ } catch (e) {}
127
+ const textSnippet = function() {
128
+ try {
129
+ const candidates = document.querySelectorAll("h1, h2, h3, h4, p, label, button, form, div, span");
130
+ let combined = "", count = 0;
131
+ for (const node of candidates) {
132
+ if (count >= 30 || combined.length >= 2e3) break;
133
+ if (!node || "string" != typeof node.innerText) continue;
134
+ if (!node.offsetWidth && !node.offsetHeight && !node.getClientRects().length) continue;
135
+ const text = node.innerText.replace(/\s+/g, " ").trim();
136
+ text && (combined += `${text} `, count += 1);
137
+ }
138
+ if (combined = combined.trim(), combined) return truncateText(combined, 2e3);
139
+ } catch (e) {}
140
+ try {
141
+ let bodyText = document.body?.innerText || "";
142
+ return !bodyText && document.body?.textContent && (bodyText = document.body.textContent),
143
+ truncateText(bodyText.replace(/\s+/g, " ").trim(), 2e3);
144
+ } catch (e) {
145
+ return "";
146
+ }
147
+ }();
148
+ if (textSnippet) {
149
+ const lowerText = textSnippet.toLowerCase();
150
+ for (const keyword of CAPTCHA_TEXT_KEYWORDS) lowerText.includes(keyword) && (hasKeywordHit = !0,
151
+ addEvidence(evidence.text_hits, keyword));
152
+ }
153
+ try {
154
+ const lowerUrl = (window.location?.href || "").toLowerCase();
155
+ for (const hint of CAPTCHA_URL_HINTS) lowerUrl.includes(hint) && (hasUrlHit = !0,
156
+ addEvidence(evidence.url_hits, hint));
157
+ } catch (e) {}
158
+ let confidence = 0;
159
+ hasIframeHit && (confidence += .7), hasContainerHit && (confidence += .5), hasScriptHit && (confidence += .5),
160
+ hasKeywordHit && (confidence += .3), hasUrlHit && (confidence += .2), confidence = Math.min(1, confidence),
161
+ hasIframeHit && (confidence = Math.max(confidence, .8)), !hasKeywordHit || hasIframeHit || hasContainerHit || hasScriptHit || hasUrlHit || (confidence = Math.min(confidence, .4));
162
+ const detected = confidence >= .7;
163
+ let providerHint = null;
164
+ return providerSignals.recaptcha > 0 ? providerHint = "recaptcha" : providerSignals.hcaptcha > 0 ? providerHint = "hcaptcha" : providerSignals.turnstile > 0 ? providerHint = "turnstile" : providerSignals.arkose > 0 ? providerHint = "arkose" : providerSignals.awswaf > 0 ? providerHint = "awswaf" : detected && (providerHint = "unknown"),
165
+ {
166
+ detected: detected,
167
+ provider_hint: providerHint,
168
+ confidence: confidence,
169
+ evidence: evidence
170
+ };
171
+ }
13
172
  const DEFAULT_INFERENCE_CONFIG = {
14
173
  allowedTags: [ "label", "span", "div" ],
15
174
  allowedRoles: [],
@@ -157,8 +316,28 @@
157
316
  }
158
317
  return null;
159
318
  }
319
+ function normalizeNearbyText(text) {
320
+ return text ? text.replace(/\s+/g, " ").trim() : "";
321
+ }
322
+ function isInteractableElement(el) {
323
+ if (!el || !el.tagName) return !1;
324
+ const tag = el.tagName.toLowerCase(), role = el.getAttribute ? el.getAttribute("role") : null, hasTabIndex = !!el.hasAttribute && el.hasAttribute("tabindex"), hasHref = "A" === el.tagName && !!el.hasAttribute && el.hasAttribute("href");
325
+ if ([ "button", "input", "textarea", "select", "option", "details", "summary", "a" ].includes(tag)) return !("a" === tag && !hasHref);
326
+ if (role && [ "button", "link", "tab", "menuitem", "checkbox", "radio", "switch", "slider", "combobox", "textbox", "searchbox", "spinbutton" ].includes(role.toLowerCase())) return !0;
327
+ if (hasTabIndex) return !0;
328
+ if (el.onclick || el.onkeydown || el.onkeypress || el.onkeyup) return !0;
329
+ if (el.getAttribute) {
330
+ if (el.getAttribute("onclick") || el.getAttribute("onkeydown") || el.getAttribute("onkeypress") || el.getAttribute("onkeyup")) return !0;
331
+ }
332
+ return !1;
333
+ }
160
334
  function getText(el) {
161
- return el.getAttribute("aria-label") ? el.getAttribute("aria-label") : "INPUT" === el.tagName ? el.value || el.placeholder || "" : "IMG" === el.tagName ? el.alt || "" : (el.innerText || "").replace(/\s+/g, " ").trim().substring(0, 100);
335
+ if (el.getAttribute("aria-label")) return el.getAttribute("aria-label");
336
+ if ("INPUT" === el.tagName) {
337
+ const t = el.getAttribute && el.getAttribute("type") || el.type || "";
338
+ return "password" === String(t).toLowerCase() ? el.placeholder || "" : el.value || el.placeholder || "";
339
+ }
340
+ return "IMG" === el.tagName ? el.alt || "" : (el.innerText || "").replace(/\s+/g, " ").trim().substring(0, 100);
162
341
  }
163
342
  function getClassName(el) {
164
343
  if (!el || !el.className) return "";
@@ -268,11 +447,17 @@
268
447
  try {
269
448
  !1 !== options.waitForStability && await async function(options = {}) {
270
449
  const {minNodeCount: minNodeCount = 500, quietPeriod: quietPeriod = 200, maxWait: maxWait = 5e3} = options, startTime = Date.now();
450
+ try {
451
+ window.__sentience_lastMutationTs = performance.now();
452
+ } catch (e) {}
271
453
  return new Promise(resolve => {
272
454
  if (document.querySelectorAll("*").length >= minNodeCount) {
273
455
  let lastChange = Date.now();
274
456
  const observer = new MutationObserver(() => {
275
457
  lastChange = Date.now();
458
+ try {
459
+ window.__sentience_lastMutationTs = performance.now();
460
+ } catch (e) {}
276
461
  });
277
462
  observer.observe(document.body, {
278
463
  childList: !0,
@@ -288,11 +473,17 @@
288
473
  } else {
289
474
  const observer = new MutationObserver(() => {
290
475
  const currentCount = document.querySelectorAll("*").length, totalWait = Date.now() - startTime;
476
+ try {
477
+ window.__sentience_lastMutationTs = performance.now();
478
+ } catch (e) {}
291
479
  if (currentCount >= minNodeCount) {
292
480
  observer.disconnect();
293
481
  let lastChange = Date.now();
294
482
  const quietObserver = new MutationObserver(() => {
295
483
  lastChange = Date.now();
484
+ try {
485
+ window.__sentience_lastMutationTs = performance.now();
486
+ } catch (e) {}
296
487
  });
297
488
  quietObserver.observe(document.body, {
298
489
  childList: !0,
@@ -323,8 +514,15 @@
323
514
  if (!el.getBoundingClientRect) return;
324
515
  const rect = el.getBoundingClientRect();
325
516
  if (rect.width < 5 || rect.height < 5) return;
517
+ const tagName = el.tagName.toLowerCase();
518
+ if ("span" === tagName) {
519
+ if (el.closest("a")) return;
520
+ const childLink = el.querySelector("a[href]");
521
+ if (childLink && childLink.href) return;
522
+ options.debug && el.className && el.className.includes("titleline");
523
+ }
326
524
  window.sentience_registry[idx] = el;
327
- const semanticText = function(el, options = {}) {
525
+ const inputType = "input" === tagName ? toSafeString(el.getAttribute && el.getAttribute("type") || el.type || null) : null, isPasswordInput = inputType && "password" === inputType.toLowerCase(), semanticText = function(el, options = {}) {
328
526
  if (!el) return {
329
527
  text: "",
330
528
  source: null
@@ -335,10 +533,10 @@
335
533
  source: "explicit_aria_label"
336
534
  };
337
535
  if ("INPUT" === el.tagName) {
338
- const value = (el.value || el.placeholder || "").trim();
536
+ const t = el.getAttribute && el.getAttribute("type") || el.type || "", isPassword = "password" === String(t).toLowerCase(), value = (isPassword ? el.placeholder || "" : el.value || el.placeholder || "").trim();
339
537
  if (value) return {
340
538
  text: value,
341
- source: "input_value"
539
+ source: isPassword ? "input_placeholder" : "input_value"
342
540
  };
343
541
  }
344
542
  if ("IMG" === el.tagName) {
@@ -367,11 +565,7 @@
367
565
  }), textVal = semanticText.text || getText(el), inferredRole = function(el, options = {}) {
368
566
  const {enableInference: enableInference = !0} = options;
369
567
  if (!enableInference) return null;
370
- if (!function(el) {
371
- if (!el || !el.tagName) return !1;
372
- const tag = el.tagName.toLowerCase(), role = el.getAttribute ? el.getAttribute("role") : null, hasTabIndex = !!el.hasAttribute && el.hasAttribute("tabindex"), hasHref = "A" === el.tagName && !!el.hasAttribute && el.hasAttribute("href");
373
- return [ "button", "input", "textarea", "select", "option", "details", "summary", "a" ].includes(tag) ? !("a" === tag && !hasHref) : !(!role || ![ "button", "link", "tab", "menuitem", "checkbox", "radio", "switch", "slider", "combobox", "textbox", "searchbox", "spinbutton" ].includes(role.toLowerCase())) || (!!hasTabIndex || (!!(el.onclick || el.onkeydown || el.onkeypress || el.onkeyup) || !(!el.getAttribute || !(el.getAttribute("onclick") || el.getAttribute("onkeydown") || el.getAttribute("onkeypress") || el.getAttribute("onkeyup")))));
374
- }(el)) return null;
568
+ if (!isInteractableElement(el)) return null;
375
569
  const hasAriaLabel = el.getAttribute ? el.getAttribute("aria-label") : null, hasExplicitRole = el.getAttribute ? el.getAttribute("role") : null;
376
570
  if (hasAriaLabel || hasExplicitRole) return null;
377
571
  const tag = el.tagName.toLowerCase();
@@ -411,9 +605,79 @@
411
605
  }
412
606
  return null;
413
607
  }(el);
608
+ let safeValue = null, valueRedacted = null;
609
+ try {
610
+ if (void 0 !== el.value || el.getAttribute && null !== el.getAttribute("value")) if (isPasswordInput) safeValue = null,
611
+ valueRedacted = "true"; else {
612
+ const rawValue = void 0 !== el.value ? String(el.value) : String(el.getAttribute("value"));
613
+ safeValue = rawValue.length > 200 ? rawValue.substring(0, 200) : rawValue, valueRedacted = "false";
614
+ }
615
+ } catch (e) {}
616
+ const accessibleName = toSafeString(function(el) {
617
+ if (!el || !el.getAttribute) return "";
618
+ const ariaLabel = el.getAttribute("aria-label");
619
+ if (ariaLabel && ariaLabel.trim()) return ariaLabel.trim().substring(0, 200);
620
+ const labelledBy = el.getAttribute("aria-labelledby");
621
+ if (labelledBy && labelledBy.trim()) {
622
+ const ids = labelledBy.split(/\s+/).filter(id => id.trim()), texts = [];
623
+ for (const id of ids) try {
624
+ const ref = document.getElementById(id);
625
+ if (!ref) continue;
626
+ const txt = (ref.innerText || ref.textContent || ref.getAttribute?.("aria-label") || "").toString().trim();
627
+ txt && texts.push(txt);
628
+ } catch (e) {}
629
+ if (texts.length > 0) return texts.join(" ").substring(0, 200);
630
+ }
631
+ try {
632
+ if (el.labels && el.labels.length > 0) {
633
+ const t = (el.labels[0].innerText || el.labels[0].textContent || "").toString().trim();
634
+ if (t) return t.substring(0, 200);
635
+ }
636
+ } catch (e) {}
637
+ try {
638
+ const parentLabel = el.closest && el.closest("label");
639
+ if (parentLabel) {
640
+ const t = (parentLabel.innerText || parentLabel.textContent || "").toString().trim();
641
+ if (t) return t.substring(0, 200);
642
+ }
643
+ } catch (e) {}
644
+ const tag = (el.tagName || "").toUpperCase();
645
+ if ("INPUT" === tag || "TEXTAREA" === tag) {
646
+ const ph = (el.getAttribute("placeholder") || "").toString().trim();
647
+ if (ph) return ph.substring(0, 200);
648
+ }
649
+ const title = el.getAttribute("title");
650
+ return title && title.trim() ? title.trim().substring(0, 200) : "";
651
+ }(el) || null), nearbyText = isInteractableElement(el) ? function(el, options = {}) {
652
+ if (!el) return null;
653
+ const maxLen = "number" == typeof options.maxLen ? options.maxLen : 80, ownText = normalizeNearbyText(el.innerText || ""), candidates = [], collect = node => {
654
+ if (!node) return;
655
+ let text = "";
656
+ try {
657
+ text = normalizeNearbyText(node.innerText || node.textContent || "");
658
+ } catch (e) {
659
+ text = "";
660
+ }
661
+ text && text !== ownText && candidates.push(text);
662
+ };
663
+ if (collect(el.previousElementSibling), collect(el.nextElementSibling), 0 === candidates.length && el.parentElement) {
664
+ let parentText = "";
665
+ try {
666
+ parentText = normalizeNearbyText(el.parentElement.innerText || "");
667
+ } catch (e) {
668
+ parentText = "";
669
+ }
670
+ parentText && parentText !== ownText && parentText.length <= 120 && candidates.push(parentText);
671
+ }
672
+ if (0 === candidates.length) return null;
673
+ let text = candidates[0];
674
+ return text.length > maxLen && (text = text.slice(0, maxLen).trim()), text || null;
675
+ }(el, {
676
+ maxLen: 80
677
+ }) : null;
414
678
  rawData.push({
415
679
  id: idx,
416
- tag: el.tagName.toLowerCase(),
680
+ tag: tagName,
417
681
  rect: {
418
682
  x: rect.x,
419
683
  y: rect.y,
@@ -435,18 +699,27 @@
435
699
  attributes: {
436
700
  role: toSafeString(el.getAttribute("role")),
437
701
  type_: toSafeString(el.getAttribute("type")),
702
+ input_type: inputType,
438
703
  aria_label: "explicit_aria_label" === semanticText?.source ? semanticText.text : toSafeString(el.getAttribute("aria-label")),
704
+ name: accessibleName,
439
705
  inferred_label: semanticText?.source && ![ "explicit_aria_label", "input_value", "img_alt", "inner_text" ].includes(semanticText.source) ? toSafeString(semanticText.text) : null,
440
706
  label_source: semanticText?.source || null,
441
707
  inferred_role: inferredRole ? toSafeString(inferredRole) : null,
442
- href: toSafeString(el.href || el.getAttribute("href") || null),
708
+ nearby_text: toSafeString(nearbyText),
709
+ href: toSafeString(el.href || el.getAttribute("href") || el.closest && el.closest("a")?.href || null),
443
710
  class: toSafeString(getClassName(el)),
444
- value: void 0 !== el.value ? toSafeString(el.value) : toSafeString(el.getAttribute("value")),
445
- checked: void 0 !== el.checked ? String(el.checked) : null
711
+ value: null !== safeValue ? toSafeString(safeValue) : null,
712
+ value_redacted: valueRedacted,
713
+ checked: void 0 !== el.checked ? String(el.checked) : null,
714
+ disabled: void 0 !== el.disabled ? String(el.disabled) : null,
715
+ aria_checked: toSafeString(el.getAttribute("aria-checked")),
716
+ aria_disabled: toSafeString(el.getAttribute("aria-disabled")),
717
+ aria_expanded: toSafeString(el.getAttribute("aria-expanded"))
446
718
  },
447
719
  text: toSafeString(textVal),
448
720
  in_viewport: inView,
449
- is_occluded: occluded
721
+ is_occluded: occluded,
722
+ scroll_y: window.scrollY
450
723
  });
451
724
  });
452
725
  const allRawElements = [ ...rawData ];
@@ -569,6 +842,18 @@
569
842
  }(options.screenshot));
570
843
  const cleanedElements = cleanElement(processed.elements), cleanedRawElements = cleanElement(processed.raw_elements);
571
844
  cleanedElements.length, cleanedRawElements.length;
845
+ let diagnostics;
846
+ try {
847
+ const lastMutationTs = window.__sentience_lastMutationTs, now = performance.now(), quietMs = "number" == typeof lastMutationTs && Number.isFinite(lastMutationTs) ? Math.max(0, now - lastMutationTs) : null, nodeCount = document.querySelectorAll("*").length;
848
+ diagnostics = {
849
+ metrics: {
850
+ ready_state: document.readyState || null,
851
+ quiet_ms: quietMs,
852
+ node_count: nodeCount
853
+ },
854
+ captcha: detectCaptcha()
855
+ };
856
+ } catch (e) {}
572
857
  return {
573
858
  status: "success",
574
859
  url: window.location.href,
@@ -578,7 +863,8 @@
578
863
  },
579
864
  elements: cleanedElements,
580
865
  raw_elements: cleanedRawElements,
581
- screenshot: screenshot
866
+ screenshot: screenshot,
867
+ diagnostics: diagnostics
582
868
  };
583
869
  } catch (error) {
584
870
  return {
@@ -848,6 +1134,14 @@
848
1134
  timestamp: Date.now()
849
1135
  }, "*");
850
1136
  }
1137
+ function showGrid(grids, targetGridId = null) {
1138
+ grids && Array.isArray(grids) && window.postMessage({
1139
+ type: "SENTIENCE_SHOW_GRID_OVERLAY",
1140
+ grids: grids,
1141
+ targetGridId: targetGridId,
1142
+ timestamp: Date.now()
1143
+ }, "*");
1144
+ }
851
1145
  function clearOverlay() {
852
1146
  window.postMessage({
853
1147
  type: "SENTIENCE_CLEAR_OVERLAY"
@@ -868,6 +1162,7 @@
868
1162
  click: click,
869
1163
  startRecording: startRecording,
870
1164
  showOverlay: showOverlay,
1165
+ showGrid: showGrid,
871
1166
  clearOverlay: clearOverlay
872
1167
  }, window.sentience_iframe_handler_setup || (window.addEventListener("message", async event => {
873
1168
  if ("SENTIENCE_IFRAME_SNAPSHOT_REQUEST" === event.data?.type) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Sentience Semantic Visual Grounding Extractor",
4
- "version": "2.2.0",
4
+ "version": "2.7.0",
5
5
  "description": "Extract semantic visual grounding data from web pages",
6
6
  "permissions": ["activeTab", "scripting"],
7
7
  "host_permissions": ["<all_urls>"],
@@ -18,34 +18,34 @@ export function prune_for_api(val: any): any;
18
18
  export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
19
19
 
20
20
  export interface InitOutput {
21
- readonly memory: WebAssembly.Memory;
22
- readonly analyze_page: (a: number) => number;
23
- readonly analyze_page_with_options: (a: number, b: number) => number;
24
- readonly decide_and_act: (a: number) => void;
25
- readonly prune_for_api: (a: number) => number;
26
- readonly __wbindgen_export: (a: number, b: number) => number;
27
- readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
28
- readonly __wbindgen_export3: (a: number) => void;
21
+ readonly memory: WebAssembly.Memory;
22
+ readonly analyze_page: (a: number) => number;
23
+ readonly analyze_page_with_options: (a: number, b: number) => number;
24
+ readonly decide_and_act: (a: number) => void;
25
+ readonly prune_for_api: (a: number) => number;
26
+ readonly __wbindgen_export: (a: number, b: number) => number;
27
+ readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
28
+ readonly __wbindgen_export3: (a: number) => void;
29
29
  }
30
30
 
31
31
  export type SyncInitInput = BufferSource | WebAssembly.Module;
32
32
 
33
33
  /**
34
- * Instantiates the given `module`, which can either be bytes or
35
- * a precompiled `WebAssembly.Module`.
36
- *
37
- * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
38
- *
39
- * @returns {InitOutput}
40
- */
34
+ * Instantiates the given `module`, which can either be bytes or
35
+ * a precompiled `WebAssembly.Module`.
36
+ *
37
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
38
+ *
39
+ * @returns {InitOutput}
40
+ */
41
41
  export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
42
42
 
43
43
  /**
44
- * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
45
- * for everything else, calls `WebAssembly.instantiate` directly.
46
- *
47
- * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
48
- *
49
- * @returns {Promise<InitOutput>}
50
- */
44
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
45
+ * for everything else, calls `WebAssembly.instantiate` directly.
46
+ *
47
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
48
+ *
49
+ * @returns {Promise<InitOutput>}
50
+ */
51
51
  export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;