newmark-agent 0.5.11 → 0.5.13

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.
@@ -1545,6 +1545,7 @@ button.left-ws-item {
1545
1545
  font-size: 12px;
1546
1546
  }
1547
1547
  .md-rendered pre {
1548
+ position: relative;
1548
1549
  margin: 8px 0;
1549
1550
  padding: 10px 12px;
1550
1551
  overflow-x: auto;
@@ -2138,6 +2139,19 @@ button.left-ws-item {
2138
2139
  /* Opaque theme-tinted foundation below the transcript, rails and glass. */
2139
2140
  background-color: var(--chat-canvas);
2140
2141
  }
2142
+ .md-code-copy {
2143
+ position: absolute;
2144
+ top: 6px;
2145
+ right: 7px;
2146
+ border: 1px solid var(--glass-border-1);
2147
+ border-radius: 4px;
2148
+ background: var(--glass-bg-2);
2149
+ color: var(--text-dim);
2150
+ padding: 2px 6px;
2151
+ font-size: 10px;
2152
+ cursor: pointer;
2153
+ }
2154
+ .md-code-copy:hover { color: var(--text); }
2141
2155
 
2142
2156
  #chat-area {
2143
2157
  flex: 1;
@@ -2512,6 +2526,33 @@ button.left-ws-item {
2512
2526
  overflow: visible;
2513
2527
  }
2514
2528
 
2529
+ /* Build Block transcript is a plain timeline, never a glass surface. Keep
2530
+ this explicit and high-priority so broad chat/panel material rules cannot
2531
+ reintroduce a rounded white compositor plane around an expanded run. */
2532
+ .work-run-message,
2533
+ .conversation-work-run,
2534
+ .conversation-work-run-head,
2535
+ .conversation-work-run-body {
2536
+ background: transparent !important;
2537
+ background-image: none !important;
2538
+ backdrop-filter: none !important;
2539
+ -webkit-backdrop-filter: none !important;
2540
+ filter: none !important;
2541
+ border: 0 !important;
2542
+ border-radius: 0 !important;
2543
+ box-shadow: none !important;
2544
+ }
2545
+
2546
+ .work-run-message::before,
2547
+ .work-run-message::after,
2548
+ .conversation-work-run-head::before,
2549
+ .conversation-work-run-head::after,
2550
+ .conversation-work-run-body::before,
2551
+ .conversation-work-run-body::after {
2552
+ content: none !important;
2553
+ display: none !important;
2554
+ }
2555
+
2515
2556
  .conversation-work-run::before {
2516
2557
  content: "";
2517
2558
  position: absolute;
@@ -2589,8 +2630,8 @@ button.left-ws-item {
2589
2630
  .conversation-work-activity-list { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 5px 24px; padding: 0; border: 0; }
2590
2631
  .conversation-work-activity-item { display: grid; grid-template-columns: 17px minmax(0,1fr); gap: 7px; align-items: start; min-height: 24px; color: var(--text-dim); font: 400 11px/1.5 var(--font-ui); }
2591
2632
  .conversation-work-activity-item .nm-icon { margin-top: 2px; }
2592
- .conversation-work-display-image { display:grid; gap:6px; width:min(100%, 640px); margin:7px 0 3px 24px; padding:0; border:0; background:transparent; color:var(--text-dim); text-align:left; cursor:pointer; }
2593
- .conversation-work-display-image img { display:block; width:100%; max-height:420px; object-fit:contain; object-position:left center; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:rgba(0,0,0,.18); }
2633
+ .conversation-work-display-image { display:inline-grid; justify-items:start; gap:6px; width:fit-content !important; max-width:min(100%, 640px); margin:7px 0 3px 24px; padding:0; border:0; border-radius:0 !important; background:transparent; color:var(--text-dim); text-align:left; cursor:pointer; }
2634
+ .conversation-work-display-image img { display:block; width:auto; max-width:100%; height:auto; max-height:420px; object-fit:contain; object-position:left center; border:1px solid var(--glass-border-2); border-radius:var(--radius-sm); background:rgba(0,0,0,.18); }
2594
2635
  .conversation-work-display-image span { font:10px/1.4 var(--font-ui); }
2595
2636
  .conversation-work-display-image:hover span, .conversation-work-display-image:focus-visible span { color:var(--accent); }
2596
2637
  .work-run-collapsed-images { display:none; flex-direction:column; gap:8px; margin:0 34px 8px 0; }
@@ -4823,20 +4864,28 @@ textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mo
4823
4864
  }
4824
4865
 
4825
4866
  .conversation-image-attachments {
4826
- display: grid;
4827
- grid-template-columns: repeat(auto-fill, minmax(132px, 190px));
4867
+ display: flex;
4868
+ flex-wrap: wrap;
4869
+ align-items: flex-start;
4870
+ justify-content: flex-start;
4828
4871
  gap: 8px;
4829
4872
  margin-top: 9px;
4830
4873
  }
4874
+ .chat-msg.user .conversation-image-attachments { justify-content: flex-end; }
4875
+ .chat-msg.assistant .conversation-image-attachments,
4876
+ .chat-msg.workflow .conversation-image-attachments { justify-content: flex-start; }
4831
4877
 
4832
4878
  .conversation-image-attachment {
4833
4879
  min-width: 0;
4834
- display: flex;
4880
+ width: fit-content !important;
4881
+ max-width: min(100%, 280px);
4882
+ display: inline-flex;
4835
4883
  flex-direction: column;
4884
+ align-items: flex-start;
4836
4885
  gap: 5px;
4837
4886
  padding: 6px;
4838
4887
  border: 1px solid var(--glass-border-2);
4839
- border-radius: var(--radius-md);
4888
+ border-radius: var(--radius-sm) !important;
4840
4889
  background: var(--glass-bg-1);
4841
4890
  color: var(--text);
4842
4891
  font: 11px/1.35 var(--font-ui);
@@ -4851,8 +4900,11 @@ textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mo
4851
4900
  }
4852
4901
 
4853
4902
  .conversation-image-attachment img {
4854
- width: 100%;
4855
- height: 112px;
4903
+ display: block;
4904
+ width: auto;
4905
+ max-width: 100%;
4906
+ height: auto;
4907
+ max-height: 180px;
4856
4908
  border-radius: var(--radius-sm);
4857
4909
  object-fit: contain;
4858
4910
  background: rgba(0,0,0,.18);
@@ -5842,6 +5894,14 @@ button.diff-block-header:active:not(:disabled),
5842
5894
  button.work-review-head:active:not(:disabled) {
5843
5895
  scale: 1;
5844
5896
  filter: none;
5897
+ }
5898
+ button.conversation-work-run-head:active:not(:disabled) {
5899
+ background: transparent !important;
5900
+ background-image: none !important;
5901
+ }
5902
+ button.shell-block-header:active:not(:disabled),
5903
+ button.diff-block-header:active:not(:disabled),
5904
+ button.work-review-head:active:not(:disabled) {
5845
5905
  background-color: revert !important;
5846
5906
  }
5847
5907
 
@@ -8814,7 +8874,7 @@ function renderMarkdownBlocks(text) {
8814
8874
  var code = codeLines.join('\n');
8815
8875
  var normalizedLanguage = lang ? normalizeCodeLanguage(lang) : 'text';
8816
8876
  var highlighted = normalizedLanguage === 'text' ? esc(code) : highlightCodeByLanguage(code, normalizedLanguage);
8817
- html += '<pre><code' + (lang ? ' data-lang="' + escAttr(lang) + '"' : '') + ' class="md-code-block language-' + escAttr(normalizedLanguage) + '">' + highlighted + '</code></pre>';
8877
+ html += '<pre><button class="md-code-copy" type="button" title="' + escAttr(t('common.copy')) + '" data-code="' + escAttr(code) + '" onclick="window.copyMarkdownCode(this)">' + esc(t('common.copy')) + '</button><code' + (lang ? ' data-lang="' + escAttr(lang) + '"' : '') + ' class="md-code-block language-' + escAttr(normalizedLanguage) + '">' + highlighted + '</code></pre>';
8818
8878
  continue;
8819
8879
  }
8820
8880
  if (trimmed === '$$' || trimmed === '\\[') {
@@ -9891,6 +9951,19 @@ function workReviewRunIds(runId, aliases) {
9891
9951
  return ids;
9892
9952
  }
9893
9953
 
9954
+ window.copyMarkdownCode = async function(button) {
9955
+ var value = String(button && button.getAttribute('data-code') || '');
9956
+ try {
9957
+ if (navigator.clipboard && navigator.clipboard.writeText) await navigator.clipboard.writeText(value);
9958
+ else {
9959
+ var helper = document.createElement('textarea');
9960
+ helper.value = value; helper.style.position = 'fixed'; helper.style.opacity = '0';
9961
+ document.body.appendChild(helper); helper.select(); document.execCommand('copy'); helper.remove();
9962
+ }
9963
+ if (button) { button.textContent = t('common.copied'); setTimeout(function() { button.textContent = t('common.copy'); }, 1200); }
9964
+ } catch (e) {}
9965
+ };
9966
+
9894
9967
  function upsertWorkReviewRecord(ui, diffs, runId, aliases) {
9895
9968
  if (!ui) return null;
9896
9969
  if (!Array.isArray(ui.workReviews)) ui.workReviews = [];
@@ -9969,7 +10042,9 @@ var STREAMING_LARGE_TEXT_INTERVAL_MS = 100;
9969
10042
 
9970
10043
  function updateMsg(div, text, role, mode, model, options) {
9971
10044
  if (!div) return;
10045
+ var preserveRunFinalResponse = div.classList && div.classList.contains('run-final-response');
9972
10046
  if (role) div.className = 'chat-msg ' + role;
10047
+ if (preserveRunFinalResponse) div.classList.add('run-final-response');
9973
10048
  text = redactSensitiveText(text);
9974
10049
  div._newmarkMessageText = String(text || '');
9975
10050
  var body = div.querySelector('.msg-body');
@@ -11167,6 +11242,7 @@ function presentedWorkRunEvents(run, includeGuides) {
11167
11242
  var rawEvents = (run.events || []).filter(publicWorkEvent).filter(function(event) {
11168
11243
  return includeGuides !== false || !(String(event && event.type || '').toLowerCase().indexOf('guide') === 0 || !!(event && event.guide));
11169
11244
  }).sort(compareConversationWorkEvents);
11245
+ var terminalAssistantResponse = terminalAssistantResponseForRun(run);
11170
11246
  var terminalInterrupted = ['interrupted', 'force_interrupted'].indexOf(String(run && run.status || '')) >= 0;
11171
11247
  var events = [];
11172
11248
  var publicText = '';
@@ -11193,6 +11269,10 @@ function presentedWorkRunEvents(run, includeGuides) {
11193
11269
  // response boundary, while retaining every distinct provider reply.
11194
11270
  publicText = '';
11195
11271
  while (events.length && ['public_text', 'partial_text'].indexOf(String(events[events.length - 1].type || '').toLowerCase()) >= 0) events.pop();
11272
+ // If an interrupted run never produced final_response, its last public
11273
+ // response becomes the standalone Agent boundary below the Build. Do
11274
+ // not keep the same text inside the expanded Build as a duplicate.
11275
+ if (terminalAssistantResponse && terminalAssistantResponse.interrupted && terminalAssistantResponse.event === rawEvent) continue;
11196
11276
  events.push(rawEvent);
11197
11277
  continue;
11198
11278
  }
@@ -11946,6 +12026,47 @@ function renderConversationHistoryFirst(target) {
11946
12026
  }
11947
12027
 
11948
12028
  function renderChatMessages(messages, target) {
12029
+ var liveArea = els['chat-area'];
12030
+ if (!liveArea) return;
12031
+ var previousRendered = Array.isArray(state.renderedChatMessages) ? state.renderedChatMessages.slice() : [];
12032
+ var previousHtml = liveArea.innerHTML;
12033
+ var previousScrollTop = liveArea.scrollTop;
12034
+ var wasAtBottom = shouldAutoScroll(liveArea);
12035
+ var stagingArea = liveArea.cloneNode(false);
12036
+ els['chat-area'] = stagingArea;
12037
+ try {
12038
+ renderChatMessagesUnsafe(messages, target);
12039
+ liveArea.replaceChildren.apply(liveArea, Array.prototype.slice.call(stagingArea.childNodes));
12040
+ if (wasAtBottom) _chatShouldAutoScroll = true;
12041
+ else liveArea.scrollTop = previousScrollTop;
12042
+ } catch (error) {
12043
+ state.renderedChatMessages = previousRendered;
12044
+ liveArea.innerHTML = previousHtml;
12045
+ liveArea.scrollTop = previousScrollTop;
12046
+ console.error('[ui_chat_render_failed]', error);
12047
+ showUiNotice(currentLang() === 'zh' ? '对话渲染出现异常,已保留原内容。' : 'Chat rendering failed; the previous content was preserved.', 'error', 'chat-render-failed');
12048
+ } finally {
12049
+ els['chat-area'] = liveArea;
12050
+ }
12051
+ }
12052
+
12053
+ function terminalAssistantResponseForRun(run) {
12054
+ var events = Array.isArray(run && run.events) ? run.events : [];
12055
+ for (var finalIndex = events.length - 1; finalIndex >= 0; finalIndex--) {
12056
+ if (String(events[finalIndex] && events[finalIndex].type || '').toLowerCase() !== 'final_response') continue;
12057
+ var finalContent = String(events[finalIndex] && events[finalIndex].content || '').trim();
12058
+ if (finalContent) return { content: finalContent, timestamp: events[finalIndex].timestamp || run.endedAt || '', interrupted: false, event: events[finalIndex] };
12059
+ }
12060
+ if (['interrupted', 'force_interrupted'].indexOf(String(run && run.status || '').toLowerCase()) < 0) return null;
12061
+ for (var responseIndex = events.length - 1; responseIndex >= 0; responseIndex--) {
12062
+ if (String(events[responseIndex] && events[responseIndex].type || '').toLowerCase() !== 'response') continue;
12063
+ var responseContent = String(events[responseIndex] && events[responseIndex].content || '').trim();
12064
+ if (responseContent) return { content: responseContent, timestamp: events[responseIndex].timestamp || run.endedAt || '', interrupted: true, event: events[responseIndex] };
12065
+ }
12066
+ return null;
12067
+ }
12068
+
12069
+ function renderChatMessagesUnsafe(messages, target) {
11949
12070
  var renderTarget = target || currentConversationTarget(activeConversationId());
11950
12071
  var normalizedMessages = cacheConversationMessages(messages, renderTarget);
11951
12072
  state.renderedChatMessages = normalizedMessages;
@@ -11970,6 +12091,7 @@ function renderChatMessages(messages, target) {
11970
12091
  var persistedRunsById = {};
11971
12092
  var persistedRunIndexes = {};
11972
12093
  var renderedRunIds = {};
12094
+ var recoveredAssistantRunIds = {};
11973
12095
  var messageRunRoles = {};
11974
12096
  state.guideMessageIndexByClientId = {};
11975
12097
  persistedRuns.forEach(function(run, runIndex) {
@@ -11988,26 +12110,20 @@ function renderChatMessages(messages, target) {
11988
12110
  if (!messageRunRoles[runId]) messageRunRoles[runId] = {};
11989
12111
  if (role === 'user' || role === 'assistant') messageRunRoles[runId][role] = true;
11990
12112
  });
11991
- function finalResponseForRun(run) {
11992
- var events = Array.isArray(run && run.events) ? run.events : [];
11993
- for (var eventIndex = events.length - 1; eventIndex >= 0; eventIndex--) {
11994
- if (String(events[eventIndex] && events[eventIndex].type || '').toLowerCase() !== 'final_response') continue;
11995
- var content = String(events[eventIndex] && events[eventIndex].content || '').trim();
11996
- if (content) return { content: content, timestamp: events[eventIndex].timestamp || run.endedAt || '' };
11997
- }
11998
- return null;
11999
- }
12000
12113
  function renderOwnedWorkRun(run, includeRecoveredFinal) {
12001
12114
  var runId = String(run && run.runId || '');
12002
- if (!runId || renderedRunIds[runId]) return;
12115
+ if (!runId) return;
12003
12116
  var roles = messageRunRoles[runId] || {};
12004
- if (!roles.user && String(run.primaryPrompt || '').trim()) {
12005
- addMsg('user', run.primaryPrompt, '', '', -1, { runId: runId, target: renderTarget, timestamp: run.startedAt || '', recovered: true });
12117
+ if (!renderedRunIds[runId]) {
12118
+ if (!roles.user && String(run.primaryPrompt || '').trim()) {
12119
+ addMsg('user', run.primaryPrompt, '', '', -1, { runId: runId, target: renderTarget, timestamp: run.startedAt || '', recovered: true });
12120
+ }
12121
+ renderConversationWorkRun(run, workRunBeforeElement(run));
12122
+ renderedRunIds[runId] = true;
12006
12123
  }
12007
- renderConversationWorkRun(run, workRunBeforeElement(run));
12008
- renderedRunIds[runId] = true;
12009
- if (includeRecoveredFinal && !roles.assistant) {
12010
- var recoveredFinal = finalResponseForRun(run);
12124
+ if (includeRecoveredFinal && !roles.assistant && !recoveredAssistantRunIds[runId]) {
12125
+ recoveredAssistantRunIds[runId] = true;
12126
+ var recoveredFinal = terminalAssistantResponseForRun(run);
12011
12127
  if (recoveredFinal) addMsg('assistant', recoveredFinal.content, '', '', -1, { runId: runId, target: renderTarget, timestamp: recoveredFinal.timestamp, recovered: true });
12012
12128
  }
12013
12129
  }
@@ -12289,6 +12405,18 @@ function renderAgentWorkEvent(event) {
12289
12405
  var finalMsg = addMsg('assistant', content, event.mode || state.mode, event.model || state.model, undefined, { runId: event.runId || '', target: workRun.target || currentConversationTarget(eventConversationId) });
12290
12406
  markFinalResponseMsg(eventConversationId, content, finalMsg);
12291
12407
  }
12408
+ } else if (workRun && (['interrupted', 'force_interrupted'].indexOf(String(type).toLowerCase()) >= 0
12409
+ || (type === 'status' && ['interrupted', 'force_interrupted'].indexOf(String(event.status || workRun.status || '').toLowerCase()) >= 0))) {
12410
+ ui.activeWorkflowText = '';
12411
+ ui.activeWorkflowMsg = null;
12412
+ ui._streamFlushPending = false;
12413
+ ui._lastLargeStreamRenderAt = 0;
12414
+ var interruptedResponse = terminalAssistantResponseForRun(workRun);
12415
+ if (interruptedResponse && interruptedResponse.content) {
12416
+ var interruptedMsg = addMsg('assistant', interruptedResponse.content, event.mode || state.mode, event.model || state.model, undefined, { runId: event.runId || workRun.runId || '', target: workRun.target || currentConversationTarget(eventConversationId) });
12417
+ markFinalResponseMsg(eventConversationId, interruptedResponse.content, interruptedMsg);
12418
+ }
12419
+ finishToolBatch(eventConversationId);
12292
12420
  } else if (type === 'tool_call' && !workRun) {
12293
12421
  upsertToolEvent(event, '');
12294
12422
  } else if (type === 'tool_result' && !workRun) {
@@ -12359,6 +12487,33 @@ function replayActiveAgentWorkEvents() {
12359
12487
  }
12360
12488
 
12361
12489
  var _conversationsRenderPending = false;
12490
+ var _contextWindowRefreshTimer = null;
12491
+ var _contextWindowRefreshInFlight = false;
12492
+ var _contextWindowRefreshTargetKey = '';
12493
+
12494
+ function scheduleActiveContextWindowRefresh(target) {
12495
+ if (!api.getState || !target || !isActiveConversationTarget(target)) return;
12496
+ var targetKey = runtimeKeyFor(target.workspaceId, target.conversationId);
12497
+ _contextWindowRefreshTargetKey = targetKey;
12498
+ if (_contextWindowRefreshTimer !== null) return;
12499
+ _contextWindowRefreshTimer = window.setTimeout(function() {
12500
+ _contextWindowRefreshTimer = null;
12501
+ if (_contextWindowRefreshInFlight || !isActiveConversationTarget(target)) return;
12502
+ _contextWindowRefreshInFlight = true;
12503
+ api.getState(target).then(function(snapshot) {
12504
+ if (!snapshot || !isActiveConversationTarget(target) || _contextWindowRefreshTargetKey !== targetKey) return;
12505
+ if (snapshot.contextWindow !== undefined) {
12506
+ state.contextWindow = snapshot.contextWindow;
12507
+ window.renderContextWindow();
12508
+ }
12509
+ if (snapshot.contextCompression !== undefined) state.contextCompression = snapshot.contextCompression;
12510
+ if (state.rightTab === 'status') window.renderRightStatusPanel();
12511
+ }).catch(function(){}).then(function() {
12512
+ _contextWindowRefreshInFlight = false;
12513
+ });
12514
+ }, 120);
12515
+ }
12516
+
12362
12517
  function scheduleConversationsRender() {
12363
12518
  if (_conversationsRenderPending) return;
12364
12519
  _conversationsRenderPending = true;
@@ -12426,6 +12581,15 @@ function appendAgentWorkEvent(event) {
12426
12581
  if (active) {
12427
12582
  setWorking(!!runningConversationRecord(activeConversationId()) || currentFlowRunning());
12428
12583
  updateSubmitButtonState();
12584
+ // Refresh snapshots only at semantic boundaries. Text/thought deltas can
12585
+ // arrive hundreds of times per second; issuing IPC snapshots for each
12586
+ // delta creates avoidable renderer/runtime contention and used to make a
12587
+ // healthy utility runtime look like a mysteriously interrupted run.
12588
+ var refreshableLiveEvent = event.type === 'status'
12589
+ || event.type === 'tool_result'
12590
+ || event.type === 'usage'
12591
+ || event.type === 'message_end';
12592
+ if (refreshableLiveEvent) scheduleActiveContextWindowRefresh(target);
12429
12593
  }
12430
12594
  if (active && event.type === 'tool_result' && ['linked_plan', 'task_read', 'task_create', 'task', 'subagent_create', 'SubAgent', 'subagent_send', 'subagent_read', 'subagent_close'].indexOf(String(event.toolName || '')) >= 0 && api.getState) {
12431
12595
  var eventWorkspaceKey = currentWorkspaceKey();
@@ -12441,6 +12605,12 @@ function appendAgentWorkEvent(event) {
12441
12605
  var terminalWorkspaceKey = currentWorkspaceKey();
12442
12606
  api.getState(target).then(function(snapshot) {
12443
12607
  if (!isActiveConversationTarget(target) || terminalWorkspaceKey !== currentWorkspaceKey()) return;
12608
+ if (snapshot && snapshot.contextWindow !== undefined) {
12609
+ state.contextWindow = snapshot.contextWindow;
12610
+ window.renderContextWindow();
12611
+ }
12612
+ if (snapshot && snapshot.contextCompression !== undefined) state.contextCompression = snapshot.contextCompression;
12613
+ if (state.rightTab === 'status') window.renderRightStatusPanel();
12444
12614
  // Backend-owned Goal continuations have no renderer send promise to
12445
12615
  // return the final snapshot. Refresh on the terminal work event so a
12446
12616
  // completed Goal clears its bar and restores Build immediately.
@@ -16069,7 +16239,7 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
16069
16239
  applyAutoRouteRatingState(s);
16070
16240
  hydrateConversationBranchState(s);
16071
16241
  syncWorkRunsSnapshot(s.workRuns, lockedTarget);
16072
- renderChatMessages(s.chatMessages || []);
16242
+ if (Array.isArray(s.chatMessages)) renderChatMessages(s.chatMessages, lockedTarget);
16073
16243
  }
16074
16244
  if (s && s.queued) {
16075
16245
  var refreshedQueue = setBackendQueueForTarget(s.queued, lockedTarget);
@@ -21564,6 +21734,18 @@ function initializeBrowserGuest(view) {
21564
21734
  addMsg('assistant', '[Browser] Load failed: ' + e.errorDescription, 'error', '');
21565
21735
  }
21566
21736
  });
21737
+ // Keep target=_blank/window.open inside the embedded browser. Electron's
21738
+ // webview otherwise creates an external window that has no address bar or
21739
+ // reload control, so a popup page could not be refreshed in-place.
21740
+ view.addEventListener('new-window', function(e) {
21741
+ var popupUrl = String(e && e.url || '').trim();
21742
+ if (!popupUrl || !/^(?:https?:|about:blank|newmark-preview:)/i.test(popupUrl)) return;
21743
+ if (e && typeof e.preventDefault === 'function') e.preventDefault();
21744
+ rememberBrowserUrl(popupUrl, true, target);
21745
+ var input = els['browser-url'];
21746
+ if (input && isActiveConversationTarget(target)) input.value = popupUrl;
21747
+ navigateBrowserView(view, popupUrl);
21748
+ });
21567
21749
  var current = '';
21568
21750
  try { current = view.getURL ? view.getURL() : ''; } catch { current = ''; }
21569
21751
  if (!current && !view.getAttribute('src')) view.setAttribute('src', browserRetainedUrls[targetKey] || 'about:blank');