@quanta-intellect/vessel-browser 0.1.145 → 0.1.146

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 (2) hide show
  1. package/out/main/index.js +265 -61
  2. package/package.json +1 -1
package/out/main/index.js CHANGED
@@ -682,15 +682,6 @@ function loadTrustedAppURL(wc, url) {
682
682
  }
683
683
  return wc.loadURL(parsed.toString());
684
684
  }
685
- const urlSafety = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
686
- __proto__: null,
687
- assertPermittedNavigationURL,
688
- assertSafeURL,
689
- isSafeNavigationURL,
690
- loadInternalDataURL,
691
- loadPermittedNavigationURL,
692
- loadTrustedAppURL
693
- }, Symbol.toStringTag, { value: "Module" }));
694
685
  const MAX_CUSTOM_HISTORY = 50;
695
686
  const READER_MODE_DATA_URL_PREFIX = "data:text/html;charset=utf-8,";
696
687
  const logger$B = createLogger("Tab");
@@ -7806,6 +7797,96 @@ function isClickReadLoop(names) {
7806
7797
  }
7807
7798
  return clickReadPairs >= 2;
7808
7799
  }
7800
+ const CLICK_READ_LOOP_SUPPRESS_THRESHOLD = 3;
7801
+ function classifyClickFailure(output) {
7802
+ if (/Error\[hidden\]/i.test(output)) return "hidden";
7803
+ if (/Error\[stale-index\]/i.test(output)) return "stale";
7804
+ if (/^\s*Error:/i.test(output)) return "other";
7805
+ return null;
7806
+ }
7807
+ function buildClickReadLoopIntervention(strikes, lastClickFailureKind) {
7808
+ if (strikes <= 0) return null;
7809
+ if (strikes >= CLICK_READ_LOOP_SUPPRESS_THRESHOLD) {
7810
+ const lines = [
7811
+ `Error: Suppressed repeated click — you have alternated click and read_page ${strikes} times without making progress and the clicks are not landing.`,
7812
+ `Stop calling click. Instead do one of: scroll (scroll or scroll_to_element) to load more of the page then read_page to refresh, inspect_element on a specific indexed result, or answer from the results already visible in the conversation.`
7813
+ ];
7814
+ if (lastClickFailureKind === "hidden") {
7815
+ lines.push(
7816
+ `The last click target was hidden / not laid out — scrolling toward it first usually reveals it.`
7817
+ );
7818
+ } else if (lastClickFailureKind === "stale") {
7819
+ lines.push(
7820
+ `The last click target was stale — refresh page state with read_page and choose a currently listed target before clicking again.`
7821
+ );
7822
+ }
7823
+ return { kind: "suppress", message: lines.join("\n") };
7824
+ }
7825
+ if (strikes >= 2) {
7826
+ const lines = [
7827
+ `[System] You are alternating between click and read_page without advancing the task, and the last click did not complete.`,
7828
+ `The click result already includes a page snapshot, so do not read_page after every click.`
7829
+ ];
7830
+ if (lastClickFailureKind === "hidden") {
7831
+ lines.push(
7832
+ `The click failed on a hidden element — call scroll (scroll or scroll_to_element) to reveal it, then read_page to refresh visible elements, before clicking again.`
7833
+ );
7834
+ } else if (lastClickFailureKind === "stale") {
7835
+ lines.push(
7836
+ `The click failed on a stale element index — call read_page to refresh current indexes before clicking again.`
7837
+ );
7838
+ } else {
7839
+ lines.push(
7840
+ `If you need detail on a specific element, use inspect_element. Otherwise continue the original task directly.`
7841
+ );
7842
+ }
7843
+ return { kind: "nudge", message: lines.join("\n") };
7844
+ }
7845
+ return {
7846
+ kind: "nudge",
7847
+ message: `[System] You are alternating between click and read_page without advancing the task. The click result already includes a page snapshot when it navigates, so do not read_page after every click. If you need detail on a specific element, use inspect_element. Otherwise continue the original task directly.`
7848
+ };
7849
+ }
7850
+ class ClickReadLoopGuard {
7851
+ recentToolNames = [];
7852
+ strikes = 0;
7853
+ lastClickFailureKind = null;
7854
+ beforeTool(toolName) {
7855
+ if (toolName === "click" && this.strikes >= CLICK_READ_LOOP_SUPPRESS_THRESHOLD && isClickReadLoop(this.recentToolNames)) {
7856
+ return buildClickReadLoopIntervention(
7857
+ this.strikes,
7858
+ this.lastClickFailureKind
7859
+ );
7860
+ }
7861
+ return null;
7862
+ }
7863
+ afterToolResult(toolName, output, succeeded) {
7864
+ if (toolName === "click") {
7865
+ this.lastClickFailureKind = succeeded ? null : classifyClickFailure(output);
7866
+ }
7867
+ this.recentToolNames.push(toolName);
7868
+ if (this.recentToolNames.length > 8) this.recentToolNames.shift();
7869
+ if (toolName === "click" && succeeded) {
7870
+ this.strikes = 0;
7871
+ return null;
7872
+ }
7873
+ if (toolName !== "click" && toolName !== "read_page") {
7874
+ this.strikes = 0;
7875
+ return null;
7876
+ }
7877
+ if (isClickReadLoop(this.recentToolNames) && this.lastClickFailureKind) {
7878
+ this.strikes += 1;
7879
+ if (this.strikes >= CLICK_READ_LOOP_SUPPRESS_THRESHOLD) {
7880
+ return null;
7881
+ }
7882
+ return buildClickReadLoopIntervention(
7883
+ this.strikes,
7884
+ this.lastClickFailureKind
7885
+ );
7886
+ }
7887
+ return null;
7888
+ }
7889
+ }
7809
7890
  const TERMINAL_TOOL_RESULT = "__VESSEL_TERMINAL_TOOL_RESULT__";
7810
7891
  const logger$w = createLogger("PromptCache");
7811
7892
  function shortHash(value) {
@@ -7966,8 +8047,7 @@ class AnthropicProvider {
7966
8047
  try {
7967
8048
  const maxIterations = getEffectiveMaxIterations();
7968
8049
  let iterationsUsed = 0;
7969
- const recentToolNames = [];
7970
- let clickReadLoopNudged = false;
8050
+ const clickReadLoopGuard = new ClickReadLoopGuard();
7971
8051
  for (let i = 0; i < maxIterations; i++) {
7972
8052
  iterationsUsed = i + 1;
7973
8053
  const stream = this.client.messages.stream(
@@ -8074,6 +8154,7 @@ class AnthropicProvider {
8074
8154
  break;
8075
8155
  }
8076
8156
  const toolResults = [];
8157
+ const loopNudges = [];
8077
8158
  for (const tb of toolUseBlocks) {
8078
8159
  if (tb._malformedArgs !== void 0) {
8079
8160
  onChunk(`
@@ -8087,6 +8168,19 @@ class AnthropicProvider {
8087
8168
  });
8088
8169
  continue;
8089
8170
  }
8171
+ const clickLoopPreflight = clickReadLoopGuard.beforeTool(tb.name);
8172
+ if (clickLoopPreflight?.kind === "suppress") {
8173
+ onChunk(`
8174
+ <<tool:click:↻ loop suppressed>>
8175
+ `);
8176
+ toolResults.push({
8177
+ type: "tool_result",
8178
+ tool_use_id: tb.id,
8179
+ content: clickLoopPreflight.message,
8180
+ is_error: true
8181
+ });
8182
+ continue;
8183
+ }
8090
8184
  const argSummary = [tb.input.url, tb.input.query, tb.input.text, tb.input.direction].map((v) => typeof v === "string" ? v : "").find((v) => v.length > 0) ?? "";
8091
8185
  onChunk(`
8092
8186
  <<tool:${tb.name}${argSummary ? ":" + argSummary : ""}>>
@@ -8101,6 +8195,7 @@ class AnthropicProvider {
8101
8195
  if (result === TERMINAL_TOOL_RESULT) {
8102
8196
  return;
8103
8197
  }
8198
+ const toolSucceeded = !/^Error:/i.test(result.trim());
8104
8199
  let parsedRich = null;
8105
8200
  try {
8106
8201
  const parsed = JSON.parse(result);
@@ -8132,16 +8227,18 @@ class AnthropicProvider {
8132
8227
  content: result
8133
8228
  });
8134
8229
  }
8135
- recentToolNames.push(tb.name);
8136
- if (recentToolNames.length > 8) recentToolNames.shift();
8230
+ const clickLoopIntervention = clickReadLoopGuard.afterToolResult(
8231
+ tb.name,
8232
+ result,
8233
+ toolSucceeded
8234
+ );
8235
+ if (clickLoopIntervention?.kind === "nudge") {
8236
+ loopNudges.push(clickLoopIntervention.message);
8237
+ }
8137
8238
  }
8138
8239
  messages.push({ role: "user", content: toolResults });
8139
- if (!clickReadLoopNudged && recentToolNames.length >= 6 && isClickReadLoop(recentToolNames)) {
8140
- clickReadLoopNudged = true;
8141
- messages.push({
8142
- role: "user",
8143
- content: `You are alternating between click and read_page without advancing the task. The click result already includes a page snapshot when it navigates — you do not need read_page after every click. If you need detail on a specific element, use inspect_element instead. If you have enough context, proceed with the next action directly.`
8144
- });
8240
+ for (const nudge of loopNudges) {
8241
+ messages.push({ role: "user", content: nudge });
8145
8242
  }
8146
8243
  }
8147
8244
  if (iterationsUsed >= maxIterations) {
@@ -9432,10 +9529,9 @@ class OpenAICompatProvider {
9432
9529
  let highlightCompletionRecoveryCount = 0;
9433
9530
  let compactCorrectionCount = 0;
9434
9531
  const recentCompactToolSignatures = [];
9435
- const recentToolNames = [];
9436
9532
  const successfulToolNames = [];
9437
9533
  const searchLoopGuard = new SearchLoopGuard(isSearchContextResettingTool);
9438
- let clickReadLoopNudged = false;
9534
+ const clickReadLoopGuard = new ClickReadLoopGuard();
9439
9535
  for (let i = 0; i < maxIterations; i++) {
9440
9536
  iterationsUsed = i + 1;
9441
9537
  let textAccum = "";
@@ -9725,6 +9821,19 @@ class OpenAICompatProvider {
9725
9821
  }
9726
9822
  continue;
9727
9823
  }
9824
+ const clickLoopPreflight = clickReadLoopGuard.beforeTool(tc.name);
9825
+ if (clickLoopPreflight?.kind === "suppress") {
9826
+ onChunk(`
9827
+ <<tool:click:↻ loop suppressed>>
9828
+ `);
9829
+ messages.push({
9830
+ role: "tool",
9831
+ tool_call_id: tc.id,
9832
+ content: clickLoopPreflight.message
9833
+ });
9834
+ compactCorrectionCount += 1;
9835
+ continue;
9836
+ }
9728
9837
  const argSummary = [args.url, args.query, args.text, args.direction].map((v) => typeof v === "string" ? v : "").find((v) => v.length > 0) ?? "";
9729
9838
  onChunk(`
9730
9839
  <<tool:${tc.name}${argSummary ? ":" + argSummary : ""}>>
@@ -9762,15 +9871,11 @@ class OpenAICompatProvider {
9762
9871
  searchToolQuery,
9763
9872
  toolSucceeded
9764
9873
  );
9765
- recentToolNames.push(tc.name);
9766
- if (recentToolNames.length > 8) recentToolNames.shift();
9767
- if (!clickReadLoopNudged && recentToolNames.length >= 6 && isClickReadLoop(recentToolNames)) {
9768
- clickReadLoopNudged = true;
9769
- messages.push({
9770
- role: "user",
9771
- content: `[System] You are alternating between click and read_page without advancing the task. The click result already includes a page snapshot when it navigates — you do not need read_page after every click. If you need detail on a specific element, use inspect_element instead. If you have enough context, proceed with the next action directly.`
9772
- });
9773
- }
9874
+ const clickLoopIntervention = clickReadLoopGuard.afterToolResult(
9875
+ tc.name,
9876
+ toolContent,
9877
+ toolSucceeded
9878
+ );
9774
9879
  compactCorrectionCount = 0;
9775
9880
  iterationToolResultPreviews.push(toolContent);
9776
9881
  messages.push({
@@ -9778,6 +9883,9 @@ class OpenAICompatProvider {
9778
9883
  tool_call_id: tc.id,
9779
9884
  content: toolContent
9780
9885
  });
9886
+ if (clickLoopIntervention?.kind === "nudge") {
9887
+ messages.push({ role: "user", content: clickLoopIntervention.message });
9888
+ }
9781
9889
  }
9782
9890
  const followUpReminder = followUpReminderForProfile(
9783
9891
  this.agentToolProfile,
@@ -10449,12 +10557,25 @@ function buildCodexFlightPriceEvidenceRecoveryInput(userMessage, assistantText,
10449
10557
  ]
10450
10558
  };
10451
10559
  }
10452
- function buildCodexFailedClickRecoveryInput(attemptedTarget, latestToolResultPreview, failedClickCount = 1) {
10560
+ function buildCodexFailedClickRecoveryInput(attemptedTarget, latestToolResultPreview, failedClickCount = 1, errorOutput = "") {
10453
10561
  const stateReminder = buildLatestStateReminder(latestToolResultPreview);
10562
+ const clickFailureKind = classifyClickFailure(errorOutput);
10454
10563
  const lines = [
10455
- `[System] The previous click did not complete${attemptedTarget ? ` for ${attemptedTarget}` : ""}.`,
10456
- `Take the next step yourself: try a different target, refresh the page state with read_page, call inspect_element on the intended element, or answer from the results already visible in the conversation. Do not ask the user to inspect or click the result for you.`
10564
+ `[System] The previous click did not complete${attemptedTarget ? ` for ${attemptedTarget}` : ""}.`
10457
10565
  ];
10566
+ if (clickFailureKind === "hidden") {
10567
+ lines.push(
10568
+ `The click target was hidden / not laid out (collapsed, lazy-loaded, or virtual-scroll). Call scroll or scroll_to_element toward it to reveal it, then read_page to refresh visible elements, before clicking again — or inspect_element on the intended index, or answer from the results already visible. Do not ask the user to inspect or click the result for you.`
10569
+ );
10570
+ } else if (clickFailureKind === "stale") {
10571
+ lines.push(
10572
+ `The click target was stale — the page changed since the last snapshot. Call read_page to refresh current indexes, then choose a currently listed target, inspect_element on the intended element, or answer from the results already visible. Do not ask the user to inspect or click the result for you.`
10573
+ );
10574
+ } else {
10575
+ lines.push(
10576
+ `Take the next step yourself: try a different target, refresh the page state with read_page, call inspect_element on the intended element, or answer from the results already visible in the conversation. Do not ask the user to inspect or click the result for you.`
10577
+ );
10578
+ }
10458
10579
  if (failedClickCount >= 2) {
10459
10580
  lines.push(
10460
10581
  `You have already had multiple failed clicks without making page progress. Do not keep clicking similar search result titles. Use the latest read_page/search result text to answer, or inspect a specific indexed result/control only if essential.`
@@ -10665,8 +10786,7 @@ class CodexProvider {
10665
10786
  let flightPriceEvidenceRecoveryCount = 0;
10666
10787
  let correctionCount = 0;
10667
10788
  const recentToolSignatures = [];
10668
- const recentToolNames = [];
10669
- let clickReadLoopNudged = false;
10789
+ const clickReadLoopGuard = new ClickReadLoopGuard();
10670
10790
  let latestToolResultPreview = null;
10671
10791
  let failedClickCountSinceProgress = 0;
10672
10792
  const searchLoopGuard = new SearchLoopGuard(isRealProgressTool);
@@ -10822,6 +10942,22 @@ ${latestToolResultPreview || ""}`
10822
10942
  correctionCount += 1;
10823
10943
  continue;
10824
10944
  }
10945
+ const clickLoopPreflight = clickReadLoopGuard.beforeTool(
10946
+ prepared.prepared.name
10947
+ );
10948
+ if (clickLoopPreflight?.kind === "suppress") {
10949
+ onChunk(`
10950
+ <<tool:click:↻ loop suppressed>>
10951
+ `);
10952
+ const suppressed = createCodexToolOutput(
10953
+ prepared.prepared.callId,
10954
+ clickLoopPreflight.message
10955
+ );
10956
+ currentInput.push(suppressed);
10957
+ latestToolResultPreview = previewToolResult(suppressed.output);
10958
+ correctionCount += 1;
10959
+ continue;
10960
+ }
10825
10961
  const output = await executePreparedCodexFunctionCall(
10826
10962
  prepared.prepared,
10827
10963
  onChunk,
@@ -10849,7 +10985,8 @@ ${latestToolResultPreview || ""}`
10849
10985
  buildCodexFailedClickRecoveryInput(
10850
10986
  summarizeToolArg(prepared.prepared.args),
10851
10987
  latestToolResultPreview,
10852
- failedClickCountSinceProgress
10988
+ failedClickCountSinceProgress,
10989
+ outputText
10853
10990
  )
10854
10991
  );
10855
10992
  }
@@ -10857,17 +10994,16 @@ ${latestToolResultPreview || ""}`
10857
10994
  if (recentToolSignatures.length > 4) {
10858
10995
  recentToolSignatures.shift();
10859
10996
  }
10860
- recentToolNames.push(prepared.prepared.name);
10861
- if (recentToolNames.length > 8) recentToolNames.shift();
10862
- if (!clickReadLoopNudged && recentToolNames.length >= 6 && isClickReadLoop(recentToolNames)) {
10863
- clickReadLoopNudged = true;
10997
+ const clickLoopIntervention = clickReadLoopGuard.afterToolResult(
10998
+ prepared.prepared.name,
10999
+ outputText,
11000
+ toolSucceeded
11001
+ );
11002
+ if (clickLoopIntervention?.kind === "nudge") {
10864
11003
  currentInput.push({
10865
11004
  type: "message",
10866
11005
  role: "user",
10867
- content: [{
10868
- type: "input_text",
10869
- text: `[System] You are alternating between click and read_page without advancing the task. The click result already includes a page snapshot when it navigates, so do not read_page after every click. If you need detail on a specific element, use inspect_element. Otherwise continue the original task directly.`
10870
- }]
11006
+ content: [{ type: "input_text", text: clickLoopIntervention.message }]
10871
11007
  });
10872
11008
  }
10873
11009
  correctionCount = 0;
@@ -12091,8 +12227,7 @@ function pageBusyError(action) {
12091
12227
  return `Error: Page is still busy; ${action} timed out waiting for page scripts. Retry in a moment.`;
12092
12228
  }
12093
12229
  async function loadPermittedUrl(wc, url) {
12094
- const { assertPermittedNavigationURL: assertPermittedNavigationURL2 } = await Promise.resolve().then(() => urlSafety);
12095
- assertPermittedNavigationURL2(url);
12230
+ assertPermittedNavigationURL(url);
12096
12231
  await wc.loadURL(url);
12097
12232
  }
12098
12233
  async function executePageScript(wc, script, options) {
@@ -16432,6 +16567,60 @@ async function clickElement(wc, selector) {
16432
16567
  }));
16433
16568
  }
16434
16569
 
16570
+ // Sum offsetTop up the offsetParent chain until reaching "container",
16571
+ // giving the element's vertical position within that scroll container.
16572
+ function offsetTopWithin(el, container) {
16573
+ let top = 0;
16574
+ let node = el;
16575
+ while (node && node !== container) {
16576
+ top += node.offsetTop || 0;
16577
+ node = node.offsetParent;
16578
+ }
16579
+ return top;
16580
+ }
16581
+
16582
+ function nearestScrollableAncestor(el) {
16583
+ let node = el.parentElement;
16584
+ while (node) {
16585
+ if (node instanceof HTMLElement) {
16586
+ const style = window.getComputedStyle(node);
16587
+ if (
16588
+ (style.overflowY === "auto" || style.overflowY === "scroll") &&
16589
+ node.scrollHeight > node.clientHeight
16590
+ ) {
16591
+ return node;
16592
+ }
16593
+ }
16594
+ node = node.parentElement;
16595
+ }
16596
+ return null;
16597
+ }
16598
+
16599
+ // Wait for the element to gain a non-zero layout box, polling for up to
16600
+ // maxFrames animation frames. Lazy / virtual-scroll renderers
16601
+ // (content-visibility, intersection-triggered list items) often lay out
16602
+ // a frame or two after the scroller moves. Falls back to setTimeout when
16603
+ // the window is hidden (requestAnimationFrame does not fire then).
16604
+ function waitForBox(el, maxFrames) {
16605
+ return new Promise((resolve) => {
16606
+ let frames = 0;
16607
+ const rafAvailable =
16608
+ typeof requestAnimationFrame === "function" &&
16609
+ document.visibilityState === "visible";
16610
+ const schedule = rafAvailable
16611
+ ? (cb) => requestAnimationFrame(cb)
16612
+ : (cb) => setTimeout(cb, 16);
16613
+ const check = () => {
16614
+ const r = el.getBoundingClientRect();
16615
+ if (r.width > 0 && r.height > 0) return resolve(true);
16616
+ if (frames >= maxFrames) return resolve(false);
16617
+ frames += 1;
16618
+ schedule(check);
16619
+ };
16620
+ check();
16621
+ });
16622
+ }
16623
+
16435
16624
  const el = document.querySelector(${JSON.stringify(selector)});
16436
16625
  if (!el) return { error: "Error[stale-index]: Element not found — the page may have changed. Call read_page to refresh." };
16437
16626
 
@@ -16439,21 +16628,26 @@ async function clickElement(wc, selector) {
16439
16628
  el.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
16440
16629
  }
16441
16630
 
16442
- await new Promise((resolve) => {
16443
- let settled = false;
16444
- const finish = () => {
16445
- if (settled) return;
16446
- settled = true;
16447
- resolve(undefined);
16448
- };
16449
- if (
16450
- typeof requestAnimationFrame === "function" &&
16451
- document.visibilityState === "visible"
16452
- ) {
16453
- requestAnimationFrame(() => finish());
16631
+ // Give the renderer a brief grace to lay the element out after the
16632
+ // initial scroll. Already-visible elements resolve on the first check.
16633
+ let revealed = await waitForBox(el, 4);
16634
+
16635
+ // scrollIntoView is a no-op on zero-rect elements (collapsed, lazy, or
16636
+ // virtual-scroll content). Force the nearest scrollable ancestor to bring
16637
+ // the element's offset position into view, then wait longer for the
16638
+ // renderer to produce a layout box. This recovers many hidden targets
16639
+ // without the model having to scroll manually.
16640
+ if (!revealed) {
16641
+ const scroller = nearestScrollableAncestor(el);
16642
+ if (scroller) {
16643
+ const targetTop = offsetTopWithin(el, scroller) - scroller.clientHeight / 2;
16644
+ scroller.scrollTop = Math.max(0, targetTop);
16454
16645
  }
16455
- setTimeout(finish, 32);
16456
- });
16646
+ if (el instanceof HTMLElement) {
16647
+ el.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
16648
+ }
16649
+ revealed = await waitForBox(el, 24);
16650
+ }
16457
16651
 
16458
16652
  const rect = el.getBoundingClientRect();
16459
16653
  if (rect.width <= 0 || rect.height <= 0) {
@@ -18016,9 +18210,13 @@ Go back and select a different product.`;
18016
18210
  const clickText = `Clicked: ${elInfo.text}${tagLabel}`;
18017
18211
  const clickResult = await clickElement(wc, selector);
18018
18212
  if (clickResult.startsWith("Error:")) return clickResult;
18019
- await waitForPotentialNavigation$1(wc, beforeUrl);
18213
+ const initialNavigationWaitMs = /DOM activation/i.test(clickResult) && !elInfo.href ? 800 : void 0;
18214
+ await waitForPotentialNavigation$1(wc, beforeUrl, initialNavigationWaitMs);
18020
18215
  const afterUrl = wc.getURL();
18021
18216
  if (afterUrl !== beforeUrl) {
18217
+ if (/DOM activation/i.test(clickResult)) {
18218
+ return `${clickText} -> ${afterUrl} (recovered via DOM activation)`;
18219
+ }
18022
18220
  return `${clickText} -> ${afterUrl}`;
18023
18221
  }
18024
18222
  const overlayHint = await detectPostClickOverlay(wc);
@@ -18045,6 +18243,9 @@ ${overlayHint}`;
18045
18243
  }
18046
18244
  return `${clickText} (${clickResult})${await buildCartSuccessSuffix(wc, beforeUrl)}`;
18047
18245
  }
18246
+ if (/DOM activation/i.test(clickResult) && (!elInfo.href || elInfo.target === "_blank")) {
18247
+ return `${clickText} (${clickResult})`;
18248
+ }
18048
18249
  const activationResult = await activateElement(wc, selector);
18049
18250
  if (!activationResult.startsWith("Error:")) {
18050
18251
  await waitForPotentialNavigation$1(wc, beforeUrl);
@@ -23847,6 +24048,9 @@ All open tabs: ${allTabs.map((t) => `${t.id === activeTabId ? "→ " : ""}${t.ti
23847
24048
  let isError = false;
23848
24049
  try {
23849
24050
  output = await executeAction(name, args, actionCtx);
24051
+ if (/^\s*Error:/i.test(output)) {
24052
+ isError = true;
24053
+ }
23850
24054
  if (provider.agentToolProfile === "compact") {
23851
24055
  runtime2.updateTaskTracker(name, output);
23852
24056
  const trackerCtx = runtime2.getTaskTrackerContext();
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.145",
4
+ "version": "0.1.146",
5
5
  "description": "AI-native web browser runtime for autonomous agents with human supervision",
6
6
  "main": "./out/main/index.js",
7
7
  "bin": {