@quanta-intellect/vessel-browser 0.1.44 → 0.1.45

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.
package/out/main/index.js CHANGED
@@ -5380,7 +5380,7 @@ function buildPhaseReminder(userMessage, assistantText) {
5380
5380
  const multiClickSelectionSignals = /i(?:'| a)?ll start by clicking on the following books|i will start by clicking on the following books|i will click on the following books|clicked on five different book titles|clicked on \d+ different book titles|clicking through the selected titles|click each of the selected titles/.test(
5381
5381
  text
5382
5382
  );
5383
- const staleSelectionSignals = /cannot locate the elements to click|page structure is not being reliably captured|specific titles failed|page may have changed|stale-index/.test(
5383
+ const staleSelectionSignals = /cannot locate the elements to click|page structure is not being reliably captured|specific titles failed|page may have changed|stale-index|no visible area|not visible/.test(
5384
5384
  text
5385
5385
  );
5386
5386
  const intermediateCartDialogSignals = /(added to cart|has been added to the cart|cart confirmation)/.test(text) && /(continue shopping|search results page|return to the search results page|back button|go back)/.test(
@@ -8212,6 +8212,8 @@ const COMPACT_FOCUS_INSTRUCTIONS = [
8212
8212
  "When read_page or inspect_element gives you an element index, prefer click(index=N) over selector-based clicks.",
8213
8213
  'If a product page has no visible purchase control, scroll and call read_page(mode="visible_only") again. Do not loop on generic inspect_element calls against navigation or unrelated regions.',
8214
8214
  "After adding an item to cart and going back, ALWAYS call read_page to see the current results. The system shows which products are already in your cart — do NOT click those again. Pick a DIFFERENT product from the list. If all visible results are already in cart, scroll down for more.",
8215
+ 'On search results pages, always call read_page(mode="results_only") first. Click products by their [#N] index from the Results section. Never click filter or sort links (e.g. Used, New, Format, Price).',
8216
+ "After go_back, always call read_page before clicking. The page may have changed.",
8215
8217
  "Keep your reasoning short. Prefer taking the next tool action over writing a long plan."
8216
8218
  ];
8217
8219
  function buildInstructionBlock(instructions) {
@@ -8563,11 +8565,11 @@ function buildCompactScopedContext(page, mode, pageType = detectPageType(page))
8563
8565
  const primaryResultElements = getPrimaryResultLinks(page);
8564
8566
  const primaryResults = primaryResultElements.map(formatElement);
8565
8567
  if (primaryResults.length > 0) {
8566
- pushSection(
8567
- lines,
8568
- "### Primary Results",
8569
- primaryResults
8570
- );
8568
+ lines.push("");
8569
+ lines.push("### Results — click one of these to open a product");
8570
+ lines.push(...primaryResults.map((item) => `- ${item}`));
8571
+ lines.push("");
8572
+ lines.push("IMPORTANT: Use click(index=N) on a result above. Do NOT click filter or sort links.");
8571
8573
  }
8572
8574
  if (pageType === "FORM" || pageType === "LOGIN" || mode === "forms_only") {
8573
8575
  pushSection(
@@ -8583,7 +8585,7 @@ function buildCompactScopedContext(page, mode, pageType = detectPageType(page))
8583
8585
  ).map(formatElement);
8584
8586
  pushSection(
8585
8587
  lines,
8586
- "### Visible Controls",
8588
+ "### Page Controls (filters, sorts — avoid when selecting products)",
8587
8589
  visibleControls
8588
8590
  );
8589
8591
  }
@@ -10661,6 +10663,17 @@ function resolveTextTargetInDocument(doc, rawQuery, mode) {
10661
10663
  score += 30;
10662
10664
  }
10663
10665
  if (inViewport(el)) score += 25;
10666
+ if (tag === "a") {
10667
+ const href = htmlEl.href || "";
10668
+ const filterParams = /\b(condition|binding|format|availability|sort|filter|price|category_id)\b=[^&]/i;
10669
+ const filterPath = /\/(condition|binding|format|availability|sort|filter|price|category)\/[^/?#]+/i;
10670
+ if (filterParams.test(href) || filterPath.test(href)) {
10671
+ score -= 40;
10672
+ }
10673
+ if (/\b(used|new|paperback|hardcover|hardback|ebook|kindle|refine|clear all|remove filter)\b/.test(label)) {
10674
+ score -= 30;
10675
+ }
10676
+ }
10664
10677
  return score;
10665
10678
  }
10666
10679
  function regionBonus(el) {
@@ -11080,9 +11093,9 @@ function waitForLoad$1(wc, timeout = 5e3) {
11080
11093
  finish();
11081
11094
  return;
11082
11095
  }
11083
- wc.on("did-finish-load", onLoadEvent);
11084
- wc.on("did-stop-loading", onLoadEvent);
11085
- wc.on("did-fail-load", onLoadEvent);
11096
+ wc.once("did-finish-load", onLoadEvent);
11097
+ wc.once("did-stop-loading", onLoadEvent);
11098
+ wc.once("did-fail-load", onLoadEvent);
11086
11099
  });
11087
11100
  }
11088
11101
  function waitForPotentialNavigation$1(wc, beforeUrl, timeout = 2500) {
@@ -11135,8 +11148,8 @@ function waitForPotentialNavigation$1(wc, beforeUrl, timeout = 2500) {
11135
11148
  wc.once("did-start-loading", onStart);
11136
11149
  wc.once("did-navigate", onNavigate);
11137
11150
  wc.once("did-navigate-in-page", onNavigateInPage);
11138
- wc.on("did-stop-loading", onNativeChange);
11139
- wc.on("page-title-updated", onNativeChange);
11151
+ wc.once("did-stop-loading", onNativeChange);
11152
+ wc.once("page-title-updated", onNativeChange);
11140
11153
  });
11141
11154
  }
11142
11155
  async function getPostNavSummary(wc) {
@@ -11336,7 +11349,7 @@ async function clickElement$1(wc, selector) {
11336
11349
 
11337
11350
  const rect = el.getBoundingClientRect();
11338
11351
  if (rect.width <= 0 || rect.height <= 0) {
11339
- return { error: "Error[hidden]: Element has no visible area" };
11352
+ return { error: "Error[hidden]: Element has no visible area. It may be inside a collapsed, lazy-loaded, or virtual-scroll section. Scroll toward it (scroll or scroll_to_element) then call read_page to refresh visible elements before clicking again." };
11340
11353
  }
11341
11354
 
11342
11355
  const points = samplePoints(rect);
@@ -11903,6 +11916,12 @@ function getCartAddedSummary(url) {
11903
11916
  Already in cart (${count} items):
11904
11917
  ${items}`;
11905
11918
  }
11919
+ function clearCartState() {
11920
+ cartAddedProducts.clear();
11921
+ recentCartClicks.clear();
11922
+ clickStreakUrl = null;
11923
+ clickStreakCount = 0;
11924
+ }
11906
11925
  async function buildCartSuccessSuffix(wc, productUrl, overlayHint) {
11907
11926
  const productTitle = await getProductPageTitle(wc);
11908
11927
  recordProductAddedToCart(productUrl, productTitle);
@@ -14480,6 +14499,18 @@ WARNING: You drifted to ${drift.targetDomain} but the task requires staying on $
14480
14499
  warnings += `${cartSummary}
14481
14500
  Select a DIFFERENT product that is not in the cart. Call read_page if needed to see available results.`;
14482
14501
  }
14502
+ if (ctx.toolProfile === "compact" && name === "go_back") {
14503
+ warnings += `
14504
+ Call read_page(mode="results_only") to see available products before clicking.`;
14505
+ }
14506
+ }
14507
+ if (name === "click" && ctx.toolProfile === "compact") {
14508
+ const filterParams = /\b(condition|binding|format|availability|sort|filter|price|category_id|view)\b=[^&]/i;
14509
+ const filterPath = /\/(condition|binding|format|availability|sort|filter|price|category)\/[^/?#]+/i;
14510
+ if (filterParams.test(currentUrl) || filterPath.test(currentUrl)) {
14511
+ warnings += `
14512
+ WARNING: The clicked link appears to be a filter or sort control, not a product. If you intended to click a product, call go_back and use click(index=N) on a result from read_page(mode="results_only").`;
14513
+ }
14483
14514
  }
14484
14515
  return `
14485
14516
  [state: url=${currentUrl}, title=${JSON.stringify(wc.getTitle() || "")}, canGoBack=${tab.canGoBack()}, canGoForward=${tab.canGoForward()}, loading=${wc.isLoading()}]${warnings}`;
@@ -15713,9 +15744,14 @@ async function handleAIQuery(query, provider, activeWebContents, onChunk, onEnd,
15713
15744
  const pageType = detectPageType(pageContent);
15714
15745
  const defaultReadMode = chooseAgentReadMode(pageContent);
15715
15746
  if (provider.agentToolProfile === "compact") {
15747
+ const prevGoal = runtime2.getState().taskTracker?.goal?.trim();
15716
15748
  runtime2.ensureTaskTracker(query, pageContent.url || activeWebContents.getURL());
15749
+ if (prevGoal !== query.trim()) {
15750
+ clearCartState();
15751
+ }
15717
15752
  } else {
15718
15753
  runtime2.clearTaskTracker();
15754
+ clearCartState();
15719
15755
  }
15720
15756
  const structuredContext = provider.agentToolProfile === "compact" ? buildCompactScopedContext(
15721
15757
  pageContent,
@@ -16938,7 +16974,7 @@ async function clickElement(wc, selector) {
16938
16974
 
16939
16975
  const rect = el.getBoundingClientRect();
16940
16976
  if (rect.width <= 0 || rect.height <= 0) {
16941
- return { error: "Element is not visible" };
16977
+ return { error: "Element is not visible. It may be inside a collapsed, lazy-loaded, or virtual-scroll section. Scroll toward it (scroll or scroll_to_element) then call read_page to refresh visible elements before clicking again." };
16942
16978
  }
16943
16979
 
16944
16980
  const points = samplePoints(rect);
@@ -17841,7 +17877,7 @@ async function hoverElement(wc, selector) {
17841
17877
  el.scrollIntoView({ behavior: 'instant', block: 'center', inline: 'center' });
17842
17878
  }
17843
17879
  const rect = el.getBoundingClientRect();
17844
- if (rect.width <= 0 || rect.height <= 0) return { error: 'Error[hidden]: Element has no visible area' };
17880
+ if (rect.width <= 0 || rect.height <= 0) return { error: 'Error[hidden]: Element has no visible area. It may be inside a collapsed, lazy-loaded, or virtual-scroll section. Scroll toward it then call read_page to refresh visible elements.' };
17845
17881
  el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true }));
17846
17882
  el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: false }));
17847
17883
  const label = (el.textContent || el.tagName || 'Element').trim().slice(0, 80);
@@ -3209,6 +3209,11 @@ function interactByIndex(index, action, value) {
3209
3209
  return "Error[stale-index]: Element not found — the page may have changed. Call read_page to refresh.";
3210
3210
  }
3211
3211
  if (action === "click") {
3212
+ el.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
3213
+ const rect = el.getBoundingClientRect();
3214
+ if (rect.width <= 0 || rect.height <= 0) {
3215
+ return "Error[hidden]: Element has no visible area. It may be inside a collapsed, lazy-loaded, or virtual-scroll section. Scroll toward it, then call read_page to refresh visible elements.";
3216
+ }
3212
3217
  el.focus();
3213
3218
  el.click();
3214
3219
  if (el instanceof HTMLInputElement) {
@@ -3235,6 +3240,7 @@ function interactByIndex(index, action, value) {
3235
3240
  return "Clicked: " + (el.getAttribute("aria-label") || el.textContent?.trim().slice(0, 60) || el.tagName.toLowerCase()) + (href ? "\nhref: " + href : "");
3236
3241
  }
3237
3242
  if (action === "focus") {
3243
+ el.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
3238
3244
  el.focus();
3239
3245
  return "Focused: " + (el.getAttribute("aria-label") || el.textContent?.trim().slice(0, 60) || el.tagName.toLowerCase());
3240
3246
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quanta-intellect/vessel-browser",
3
3
  "mcpName": "io.github.unmodeled-tyler/vessel-browser",
4
- "version": "0.1.44",
4
+ "version": "0.1.45",
5
5
  "description": "AI-native web browser runtime for autonomous agents with human supervision",
6
6
  "main": "./out/main/index.js",
7
7
  "bin": {