feat(agent): Connect AI 웹사이트 탐색 기능(read_url) 추가 및 웹 스크래핑 구현

This commit is contained in:
Jay
2026-04-16 01:23:56 +09:00
parent c0a2876685
commit 1c3db89016
46 changed files with 2286 additions and 4 deletions
+33 -3
View File
@@ -78,6 +78,10 @@ Example — user says "서버 실행해줘":
<read_brain>filename.md</read_brain>
Use this to READ documents from the user's personal knowledge base.
━━━ ACTION 8: READ WEBSITES ━━━
<read_url>https://example.com</read_url>
Use this to read the textual content of any website on the internet.
CRITICAL RULES:
1. ALWAYS respond in the same language the user uses.
2. When the user asks to create, edit, delete files or run commands, you MUST use the action tags above. NEVER just show code without action tags.
@@ -817,7 +821,7 @@ class SidebarChatProvider implements vscode.WebviewViewProvider {
this._view.webview.postMessage({ type: 'streamEnd' });
this._chatHistory.push({ role: 'assistant', content: aiMessage });
const report = this._executeActions(aiMessage);
const report = await this._executeActions(aiMessage);
if (report.length > 0) {
const reportMsg = `\n\n---\n**에이전트 작업 결과**\n${report.join('\n')}`;
this._view.webview.postMessage({ type: 'streamChunk', value: reportMsg });
@@ -1006,7 +1010,7 @@ class SidebarChatProvider implements vscode.WebviewViewProvider {
this._chatHistory.push({ role: 'assistant', content: aiMessage });
// 5. Execute agent actions
const report = this._executeActions(aiMessage);
const report = await this._executeActions(aiMessage);
// 6. Agent report 추가 (있을 때만)
if (report.length > 0) {
@@ -1065,7 +1069,7 @@ class SidebarChatProvider implements vscode.WebviewViewProvider {
// --------------------------------------------------------
// Execute ALL agent actions from AI response
// --------------------------------------------------------
private _executeActions(aiMessage: string): string[] {
private async _executeActions(aiMessage: string): Promise<string[]> {
const report: string[] = [];
let rootPath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
@@ -1247,6 +1251,32 @@ class SidebarChatProvider implements vscode.WebviewViewProvider {
}
}
// ACTION 8: Read Urls (Web Scraping)
const urlRegex = /<(?:read_url|url|fetch_url)>([\s\S]*?)<\/(?:read_url|url|fetch_url)>/gi;
while ((match = urlRegex.exec(aiMessage)) !== null) {
const url = match[1].trim();
try {
// Fetch the HTML content
const { data } = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }, timeout: 10000 });
// Strip scripts and styles first
let cleaned = data.toString()
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
// Strip remaining HTML tags
.replace(/<[^>]+>/g, ' ')
// Consolidate whitespaces
.replace(/\s+/g, ' ')
.trim();
const preview = cleaned.slice(0, 500);
report.push(`🌐 웹사이트 읽기: ${url} (${cleaned.length}자)\n\`\`\`\n${preview}...\n\`\`\``);
this._chatHistory.push({ role: 'user', content: `[시스템: read_url 결과]\nURL: ${url}\n\`\`\`\n${cleaned.slice(0, 15000)}\n\`\`\`` });
} catch (err: any) {
report.push(`❌ 웹사이트 접속 실패: ${url}${err.message}`);
this._chatHistory.push({ role: 'user', content: `[시스템: read_url 실패]\n${err.message}` });
}
}
// FALLBACK: If AI used markdown code blocks with filenames instead of XML tags
if (report.length === 0) {
const fallbackRegex = /```(?:[a-zA-Z]*)?\s*\n\/\/\s*(?:file|파일):\s*([^\n]+)\n([\s\S]*?)```/gi;