mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-21 04:45:12 +00:00
* clean-up bunch of files for re-write * more clean-up and adding basic agent * Minor fix moved types into respective files. * Deleted bunch of old files backup Update gitignore Deleted a bunch of files Remove message manager Deleted old docs Update rules rename Profiler to profiler * Temporarily adding old code * Adding two small things back * backup * Implemented LangChainProvider and updated cursor rules backup LangChainProvider curosr rules * Implement tests for LangChainProvider -- unit test and integration test integration test passes integration test backup * Tool Design Tools Desing tools design * NavigationTool ready NavigationTool ready NavigationTool ready NaivgationTool ready backup * MessageManager MessageManager backup * Fixed integration test * Agent design new Updated agent design and added bunch of /NTN commands agent new design * Delete old agent design * MessageManagerReadOnly class * PlannerTool ready PlannerTool almost ready * ToolManager and DoneTool * Integration of BrowserAgent * BrowserAgent implementation v0.1 * BrowserAgent small fix v0.2 * Tool calling design too call design tool design claude * Update agent tool design with // NTN * add zod-to-json npm install * BrowserAGent v0.3 * BrowserAgent v0.4 * BrowserAgent v0.5 * fixes * Build error fixes in my NEWLY added code build errors fix * Build error fixes in old code (integration work) backup * Comment StreamEventProcessor for now, it is not used * Small build error fix * Small rename * Added integration test to check structuredLLM and changed to 4o-mini change default to nxtscape integration test * Small docstring * Simplified BrowserAgent code and added integration test Simplified BrowserAgent code BrowserAGent integrationt est * Update CLAUDE.md with project memory and instructions on how to write code Update CLAUDE.md with project memory and instructions on how to write code Project Memory * Just a mova.. Moved ToolManager outside. Build works. * TabOperations tool TabOperations Tool and fixing some test tab operations * Update CLAUDE.md * Added ClassificationTool classifiction tool classification prommpt * Refactored and simplified PlannerTool unit test and integration test * Updated Plnnaer tool * Update CLAUDE.md * BrowserAgent modified to do classification BrowserAgent with classification * minor fix to ToolManager * Instead of ToolCall and ToolResult -- just updating message manager once * minor fix to BrowserAgent integration test * Changed done to "done_tool" * Updated CLAUDE.md to reflect understanding of claude * Uncommented stream event processor * Renamed EventBus to StreamEventBus * Commented StreamEventProcessor * Event Processor * Integrated EventProcessor with BrowserAgent Added EventProcessor to BrowserAgetn * Renamed StreamEventBus to EventBus * Made EventBus required parameter in ExecutionContext * PlanGenerator rewrite PlanGenerator rewrite backup * For simple task, explicitly tell it to call done tool * Max attempts for simple task * backup * Revert "backup" This reverts commit 7d79a3d4d5774bfef79ec9827878b74edad3593f. * Consolidating where EventBus and EventProcessor are created and initialized backup * Update CLAUDE.md Update CLAUDE.md * Improving agent loop code Cleaned up processTooCall classification task * Create test-writer subAgent test-agent-prompt test agent prompt test-agent-prompt Update test-writer.md * BrowserAgent test Browseragent test BrowserAgent test * BrowserAgent refactor backup backup * Minor fixes * Minor fix * minor change -- NEW AGENT LOOP IS WORKING WELL * Update cursor rules * Small change * Improved BrowserAgent integration test Improved BrowserAgent integration test * Small change * Update CLAUDE.md * Different tools * FindElementTool is ready Find element update backup find element backup * Updated to test strings to say "tests..." * ScrollTool is ready * RefreshStateTool is updated as well * MessageManager updated * SearchTool is ready backup * Interaction Element is also ready * Add debugMessage emitter * ValidatorTool ready and tests are passing Validation Tool validator tool backup backup * GroupTabs tool ready * Registered all the tools * Planning changed to 5 steps * BrowserAgent integration test fix * Minor string changes * backup * Removed too many confusing events in EventProcessor -- there is only event.info right now * Abort control implemented backup Abort * Formatter for toolResult Formatter for toolResult backup * Always render using Markdown * Minor fix --------- Co-authored-by: Nikhil Sonti <nikhilsv92@gmail.com>
236 lines
6.2 KiB
TypeScript
236 lines
6.2 KiB
TypeScript
/**
|
|
* Common utilities and operations for bookmark tools
|
|
*/
|
|
|
|
/**
|
|
* Get the bookmark bar folder
|
|
*/
|
|
export async function getBookmarkBar(): Promise<chrome.bookmarks.BookmarkTreeNode | null> {
|
|
const tree = await chrome.bookmarks.getTree();
|
|
const root = tree[0];
|
|
|
|
for (const child of root.children || []) {
|
|
if (child.id === '1' || child.title === 'Bookmarks Bar') {
|
|
return child;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find a folder by its path (e.g., "Work/Projects/React")
|
|
*/
|
|
export async function findFolderByPath(path: string): Promise<chrome.bookmarks.BookmarkTreeNode | null> {
|
|
const parts = path.split('/').filter(p => p.length > 0);
|
|
if (parts.length === 0) return null;
|
|
|
|
// Start from bookmark bar
|
|
const bookmarkBar = await getBookmarkBar();
|
|
if (!bookmarkBar) return null;
|
|
|
|
let currentFolder = bookmarkBar;
|
|
|
|
// Navigate through the path
|
|
for (const part of parts) {
|
|
const children = await chrome.bookmarks.getChildren(currentFolder.id);
|
|
const folder = children.find(child => !child.url && child.title === part);
|
|
|
|
if (!folder) {
|
|
return null; // Path not found
|
|
}
|
|
|
|
currentFolder = folder;
|
|
}
|
|
|
|
return currentFolder;
|
|
}
|
|
|
|
/**
|
|
* Get the full path of a folder from its ID
|
|
*/
|
|
export async function getFolderPath(folderId: string): Promise<string> {
|
|
const path: string[] = [];
|
|
let currentId = folderId;
|
|
|
|
while (currentId) {
|
|
try {
|
|
const folders = await chrome.bookmarks.get(currentId);
|
|
const folder = folders[0];
|
|
|
|
if (folder.title === 'Bookmarks Bar' || !folder.parentId) {
|
|
path.unshift('Bookmarks Bar');
|
|
break;
|
|
}
|
|
|
|
path.unshift(folder.title);
|
|
currentId = folder.parentId;
|
|
} catch {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return path.join('/');
|
|
}
|
|
|
|
/**
|
|
* Find a child folder by name within a parent folder
|
|
*/
|
|
export async function findChildFolder(
|
|
parentId: string,
|
|
folderName: string
|
|
): Promise<chrome.bookmarks.BookmarkTreeNode | null> {
|
|
const children = await chrome.bookmarks.getChildren(parentId);
|
|
return children.find(child => !child.url && child.title === folderName) || null;
|
|
}
|
|
|
|
/**
|
|
* Check if a folder is a system folder
|
|
*/
|
|
export function isSystemFolder(folder: chrome.bookmarks.BookmarkTreeNode): boolean {
|
|
const systemFolders = ['Other Bookmarks', 'Mobile Bookmarks'];
|
|
return systemFolders.includes(folder.title);
|
|
}
|
|
|
|
/**
|
|
* Check if a folder is protected from deletion
|
|
*/
|
|
export function isProtectedFolder(folder: chrome.bookmarks.BookmarkTreeNode): boolean {
|
|
// Protect system folders by ID
|
|
const protectedIds = ['0', '1', '2']; // Root, Bookmarks Bar, Other Bookmarks
|
|
if (protectedIds.includes(folder.id)) {
|
|
return true;
|
|
}
|
|
|
|
// Protect by name
|
|
const protectedNames = [
|
|
'Bookmarks Bar',
|
|
'Other Bookmarks',
|
|
'Mobile Bookmarks',
|
|
'Sessions'
|
|
];
|
|
|
|
return protectedNames.includes(folder.title);
|
|
}
|
|
|
|
/**
|
|
* Recursively collect all bookmarks from a folder and its subfolders
|
|
*/
|
|
export async function collectAllBookmarksRecursively(
|
|
folderId: string,
|
|
parentTitle: string,
|
|
targetFolderToSkip?: string
|
|
): Promise<Array<{ id: string; title: string; url: string; parentTitle?: string }>> {
|
|
const allBookmarks: Array<{ id: string; title: string; url: string; parentTitle?: string }> = [];
|
|
|
|
try {
|
|
const children = await chrome.bookmarks.getChildren(folderId);
|
|
|
|
for (const child of children) {
|
|
if (child.url) {
|
|
// It's a bookmark - add it to the collection
|
|
allBookmarks.push({
|
|
id: child.id,
|
|
title: child.title,
|
|
url: child.url,
|
|
parentTitle: parentTitle
|
|
});
|
|
} else {
|
|
// It's a folder - skip target folder and recursively explore others
|
|
if (!targetFolderToSkip || child.title !== targetFolderToSkip) {
|
|
const childBookmarks = await collectAllBookmarksRecursively(
|
|
child.id,
|
|
child.title,
|
|
targetFolderToSkip
|
|
);
|
|
allBookmarks.push(...childBookmarks);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error collecting bookmarks from folder ${folderId}:`, error);
|
|
}
|
|
|
|
return allBookmarks;
|
|
}
|
|
|
|
/**
|
|
* Recursively clean up empty folders
|
|
*/
|
|
export async function cleanupEmptyFoldersRecursively(
|
|
parentFolderId: string,
|
|
targetFolderToProtect?: string
|
|
): Promise<void> {
|
|
try {
|
|
const children = await chrome.bookmarks.getChildren(parentFolderId);
|
|
const folders = children.filter(child => !child.url);
|
|
|
|
// Process folders in reverse order to handle nested cleanup properly
|
|
for (const folder of folders) {
|
|
// Skip protected folders
|
|
if ((targetFolderToProtect && folder.title === targetFolderToProtect) || isProtectedFolder(folder)) {
|
|
continue;
|
|
}
|
|
|
|
// First, recursively clean up subfolders
|
|
await cleanupEmptyFoldersRecursively(folder.id, targetFolderToProtect);
|
|
|
|
// After cleaning subfolders, check if this folder is now empty
|
|
const folderChildren = await chrome.bookmarks.getChildren(folder.id);
|
|
if (folderChildren.length === 0) {
|
|
await chrome.bookmarks.remove(folder.id);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error cleaning up folders in ${parentFolderId}:`, error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Type for bookmark item with metadata
|
|
*/
|
|
export interface BookmarkWithMetadata {
|
|
id: string;
|
|
title: string;
|
|
url: string;
|
|
parentTitle?: string;
|
|
}
|
|
|
|
/**
|
|
* Type for folder statistics
|
|
*/
|
|
export interface FolderStats {
|
|
bookmarkCount: number;
|
|
subfolderCount: number;
|
|
totalItemCount: number;
|
|
}
|
|
|
|
/**
|
|
* Move all bookmarks from source folder to destination folder (non-recursive)
|
|
*/
|
|
export async function moveBookmarksToFolder(
|
|
sourceFolderId: string,
|
|
destinationFolderId: string
|
|
): Promise<number> {
|
|
let movedCount = 0;
|
|
|
|
try {
|
|
const children = await chrome.bookmarks.getChildren(sourceFolderId);
|
|
const bookmarks = children.filter(child => child.url);
|
|
|
|
for (const bookmark of bookmarks) {
|
|
try {
|
|
await chrome.bookmarks.move(bookmark.id, {
|
|
parentId: destinationFolderId
|
|
});
|
|
movedCount++;
|
|
} catch (error) {
|
|
console.error(`Failed to move bookmark ${bookmark.title}:`, error);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error moving bookmarks from ${sourceFolderId}:`, error);
|
|
}
|
|
|
|
return movedCount;
|
|
}
|