Skip to content

Commit bec318f

Browse files
author
Tajudeen
committed
Fix and optimize web search implementation
- Switch to DuckDuckGo as primary search method (Google was being blocked) - Add DuckDuckGo redirect URL extraction to get real URLs from redirect links - Improve parsing with multiple strategies: markdown links and direct URL extraction - Add better error diagnostics with content preview - Optimize performance: early exits, smart retries, reduced wait times - Fix React duplicate key warnings in chat UI (use toolId instead of index) - Add defensive check for message editing to prevent errors
1 parent c8da853 commit bec318f

File tree

7 files changed

+332
-140
lines changed

7 files changed

+332
-140
lines changed

extensions/open-remote-ssh/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"onCommand:openremotessh.openEmptyWindowInCurrentWindow",
2727
"onCommand:openremotessh.openConfigFile",
2828
"onCommand:openremotessh.showLog",
29+
"onCommand:openremotessh.explorer.add",
2930
"onResolveRemoteAuthority:ssh-remote",
3031
"onView:sshHosts"
3132
],

src/vs/platform/webContentExtractor/electron-main/webContentExtractorService.ts

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,79 @@ export class NativeWebContentExtractorService implements IWebContentExtractorSer
9595

9696
private async extractAX(win: BrowserWindow, uri: URI): Promise<WebContentExtractResult> {
9797
await win.loadURL(uri.toString(true));
98-
win.webContents.debugger.attach('1.1');
99-
const result: { nodes: AXNode[] } = await win.webContents.debugger.sendCommand('Accessibility.getFullAXTree');
100-
const str = convertAXTreeToMarkdown(uri, result.nodes);
101-
this._logger.info(`[NativeWebContentExtractorService] Content extracted from ${uri}`);
102-
this._logger.trace(`[NativeWebContentExtractorService] Extracted content: ${str}`);
103-
return { status: 'ok', result: str };
98+
99+
// Check if this is a JSON API endpoint
100+
const isJsonApi = uri.toString(true).includes('format=json') || uri.toString(true).includes('/api/') || uri.path.includes('.json');
101+
102+
// Wait for page to load (with timeout)
103+
await Promise.race([
104+
new Promise<void>((resolve) => {
105+
win.webContents.once('dom-ready', () => {
106+
setTimeout(resolve, 500);
107+
});
108+
}),
109+
new Promise<void>((resolve) => {
110+
win.webContents.once('did-finish-load', () => {
111+
setTimeout(resolve, 500);
112+
});
113+
}),
114+
new Promise<void>((resolve) => setTimeout(resolve, 8000)) // 8 second timeout
115+
]);
116+
117+
// For JSON APIs, try to extract raw JSON using JavaScript before accessibility tree
118+
if (isJsonApi) {
119+
try {
120+
const rawText = await Promise.race([
121+
win.webContents.executeJavaScript(`
122+
(() => {
123+
// JSON APIs often render in <pre> tags or as plain text
124+
const preTag = document.querySelector('pre');
125+
if (preTag && preTag.textContent) {
126+
return preTag.textContent.trim();
127+
}
128+
if (document.body) {
129+
const bodyText = document.body.innerText || document.body.textContent || '';
130+
if (bodyText.trim()) {
131+
return bodyText.trim();
132+
}
133+
}
134+
return document.documentElement.innerText || document.documentElement.textContent || '';
135+
})()
136+
`),
137+
new Promise<string>((_, reject) => setTimeout(() => reject(new Error('Timeout')), 3000))
138+
]) as string;
139+
140+
if (rawText && rawText.trim()) {
141+
const trimmed = rawText.trim();
142+
// Validate it looks like JSON
143+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
144+
this._logger.info(`[NativeWebContentExtractorService] Raw JSON content extracted from ${uri}`);
145+
return { status: 'ok', result: trimmed };
146+
}
147+
}
148+
} catch (error) {
149+
this._logger.warn(`[NativeWebContentExtractorService] Failed to extract JSON via JavaScript from ${uri}: ${error}`);
150+
}
151+
}
152+
153+
// Fallback to accessibility tree extraction (for HTML pages or if JSON extraction failed)
154+
try {
155+
win.webContents.debugger.attach('1.1');
156+
const result: { nodes: AXNode[] } = await win.webContents.debugger.sendCommand('Accessibility.getFullAXTree');
157+
const str = convertAXTreeToMarkdown(uri, result.nodes);
158+
this._logger.info(`[NativeWebContentExtractorService] Content extracted from ${uri}`);
159+
this._logger.trace(`[NativeWebContentExtractorService] Extracted content: ${str.substring(0, 200)}...`);
160+
return { status: 'ok', result: str };
161+
} finally {
162+
// Detach debugger when done
163+
try {
164+
if (win.webContents.debugger.isAttached()) {
165+
win.webContents.debugger.detach();
166+
}
167+
} catch (e) {
168+
// Ignore detach errors
169+
}
170+
}
104171
}
105172

106173
private interceptRedirects(win: BrowserWindow, uri: URI, store: DisposableStore) {

src/vs/workbench/contrib/comments/browser/commentsController.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,12 @@ export class CommentController implements IEditorContribution {
10841084
}
10851085

10861086
private onEditorMouseDown(e: IEditorMouseEvent): void {
1087-
this.mouseDownInfo = (e.target.element?.className.indexOf('comment-range-glyph') ?? -1) >= 0 ? parseMouseDownInfoFromEvent(e) : null;
1087+
const element = e.target.element;
1088+
const hasCommentGlyph = element && (
1089+
(typeof element.className === 'string' && element.className.indexOf('comment-range-glyph') >= 0) ||
1090+
(element.classList && element.classList.contains('comment-range-glyph'))
1091+
);
1092+
this.mouseDownInfo = hasCommentGlyph ? parseMouseDownInfoFromEvent(e) : null;
10881093
}
10891094

10901095
private onEditorMouseUp(e: IEditorMouseEvent): void {

src/vs/workbench/contrib/cortexide/browser/media/cortexide.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,8 @@ body.monaco-workbench {
575575
color: var(--cortex-text-muted) !important;
576576
border-radius: 14px !important;
577577
border: 1px solid transparent !important;
578-
padding: 6px 10px !important;
578+
padding: 9px 12px !important;
579+
min-height: 40px !important;
579580
}
580581

581582
.monaco-workbench .quick-input-widget .quick-input-list .quick-input-list-entry .quick-input-list-label {

src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,15 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhost, curr
13401340
// cancel any streams on this thread - use subscribed state
13411341
const threadId = currentThreadId
13421342

1343+
// Defensive check: verify the message is still a user message before editing
1344+
const thread = chatThreadsState.allThreads[threadId]
1345+
if (!thread || !thread.messages || thread.messages[messageIdx]?.role !== 'user') {
1346+
console.error('Error while editing message: Message is not a user message or no longer exists')
1347+
setIsBeingEdited(false)
1348+
chatThreadsService.setCurrentlyFocusedMessageIdx(undefined)
1349+
return
1350+
}
1351+
13431352
await chatThreadsService.abortRunning(threadId)
13441353

13451354
// update state
@@ -3270,7 +3279,7 @@ const PlanComponent = React.memo(({ message, isCheckpointGhost, threadId, messag
32703279
<div className="text-void-fg-3 text-xs mb-2 font-medium">Expected Tools:</div>
32713280
<div className="flex flex-wrap gap-1.5">
32723281
{step.tools.map((tool, i) => (
3273-
<span key={i} className="px-2 py-0.5 bg-blue-500/10 text-blue-400 text-xs rounded border border-blue-500/20">
3282+
<span key={`${step.stepNumber}-tool-${tool}-${i}`} className="px-2 py-0.5 bg-blue-500/10 text-blue-400 text-xs rounded border border-blue-500/20">
32743283
{tool}
32753284
</span>
32763285
))}
@@ -3290,7 +3299,7 @@ const PlanComponent = React.memo(({ message, isCheckpointGhost, threadId, messag
32903299
const isError = toolMsg.type === 'tool_error'
32913300

32923301
return (
3293-
<div key={i} className={`p-2 rounded border text-xs ${
3302+
<div key={toolId} className={`p-2 rounded border text-xs ${
32943303
isSuccess ? 'bg-green-500/10 border-green-500/20' :
32953304
isError ? 'bg-red-500/10 border-red-500/20' :
32963305
'bg-blue-500/10 border-blue-500/20'

0 commit comments

Comments
 (0)