mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-22 05:15:13 +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>
223 lines
7.1 KiB
TypeScript
223 lines
7.1 KiB
TypeScript
import { z } from 'zod';
|
|
import { NxtscapeTool } from '../base/NxtscapeTool';
|
|
import { ToolConfig } from '../base/ToolConfig';
|
|
import { ExecutionContext } from '@/lib/runtime/ExecutionContext';
|
|
import { TabInfo } from './TabOperationsTool';
|
|
|
|
/**
|
|
* Schema for group tabs input
|
|
*/
|
|
export const GroupTabsInputSchema = z.object({
|
|
tabIds: z.array(z.number()).min(1), // Array of tab IDs to group (at least 1 required)
|
|
groupName: z.string().optional(), // Optional name for the group
|
|
color: z.enum(['grey', 'blue', 'red', 'yellow', 'green', 'pink', 'purple', 'cyan', 'orange']).optional(), // Group color
|
|
windowId: z.number().optional() // Optional window ID where group should be created
|
|
});
|
|
|
|
export type GroupTabsInput = z.infer<typeof GroupTabsInputSchema>;
|
|
|
|
/**
|
|
* Schema for group tabs output
|
|
*/
|
|
export const GroupTabsOutputSchema = z.object({
|
|
success: z.boolean(), // Whether the operation succeeded
|
|
groupId: z.number().optional(), // ID of the created group
|
|
groupName: z.string().optional(), // Name of the group
|
|
color: z.string(), // Color of the group
|
|
tabCount: z.number(), // Number of tabs in the group
|
|
message: z.string() // Human-readable summary message
|
|
});
|
|
|
|
export type GroupTabsOutput = z.infer<typeof GroupTabsOutputSchema>;
|
|
|
|
/**
|
|
* Tool for grouping browser tabs together
|
|
*/
|
|
export class GroupTabsTool extends NxtscapeTool<GroupTabsInput, GroupTabsOutput> {
|
|
constructor(executionContext: ExecutionContext) {
|
|
const config: ToolConfig<GroupTabsInput, GroupTabsOutput> = {
|
|
name: 'group_tabs',
|
|
description: 'Group browser tabs together. Takes an array of tab IDs and creates a group with optional name and color. Colors: grey, blue, red, yellow, green, pink, purple, cyan, orange.',
|
|
category: 'tab_management',
|
|
version: '1.0.0',
|
|
inputSchema: GroupTabsInputSchema,
|
|
outputSchema: GroupTabsOutputSchema,
|
|
examples: [
|
|
{
|
|
description: 'Group work-related tabs with a blue color',
|
|
input: {
|
|
tabIds: [123, 456],
|
|
groupName: 'Work Research',
|
|
color: 'blue'
|
|
},
|
|
output: {
|
|
success: true,
|
|
groupId: 1,
|
|
groupName: 'Work Research',
|
|
groupedCount: 2,
|
|
groupedTabs: [
|
|
{ id: 123, title: 'GitHub', url: 'https://github.com' },
|
|
{ id: 456, title: 'Documentation', url: 'https://docs.example.com' }
|
|
],
|
|
message: 'Successfully grouped 2 tabs into "Work Research"'
|
|
}
|
|
}
|
|
],
|
|
streamingConfig: {
|
|
displayName: 'Group Tabs',
|
|
icon: '📁',
|
|
progressMessage: 'Organizing tabs into groups...'
|
|
}
|
|
};
|
|
|
|
super(config, executionContext);
|
|
}
|
|
|
|
/**
|
|
* Override: Generate contextual display message based on arguments
|
|
*/
|
|
getProgressMessage(args: GroupTabsInput): string {
|
|
try {
|
|
// Parse args safely
|
|
// Note: args should already be parsed by StreamEventProcessor
|
|
|
|
const tabIds = args?.tabIds;
|
|
const groupName = args?.groupName;
|
|
|
|
if (tabIds && Array.isArray(tabIds)) {
|
|
const count = tabIds.length;
|
|
const tabText = count === 1 ? 'tab' : 'tabs';
|
|
|
|
if (groupName) {
|
|
return `Grouping ${count} ${tabText} into "${groupName}"`;
|
|
}
|
|
|
|
return `Grouping ${count} ${tabText}`;
|
|
}
|
|
|
|
return 'Organizing tabs into groups...'; // Fallback to default
|
|
} catch {
|
|
return 'Organizing tabs into groups...'; // Fallback on any error
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Override: Format group creation result for display
|
|
* Returns user-friendly group creation information
|
|
*/
|
|
FormatResultForUI(output: GroupTabsOutput): string {
|
|
if (!output.success) {
|
|
return `❌ ${output.message}`;
|
|
}
|
|
|
|
const tabCount = output.tabCount;
|
|
const tabText = tabCount === 1 ? 'tab' : 'tabs';
|
|
|
|
if (output.groupName) {
|
|
return `📁 Created "${output.groupName}" group with ${tabCount} ${tabText}`;
|
|
}
|
|
|
|
return `📁 Grouped ${tabCount} ${tabText} together`;
|
|
}
|
|
|
|
protected async execute(input: GroupTabsInput): Promise<GroupTabsOutput> {
|
|
try {
|
|
// Validate that all tab IDs exist
|
|
const allTabs = await this.getAllTabs(input.windowId);
|
|
const validTabIds = input.tabIds.filter(tabId =>
|
|
allTabs.some(tab => tab.id === tabId)
|
|
);
|
|
|
|
if (validTabIds.length === 0) {
|
|
return {
|
|
success: false,
|
|
color: input.color || 'blue',
|
|
tabCount: 0,
|
|
message: `No valid tabs found for the provided tab IDs: ${input.tabIds.join(', ')}`
|
|
};
|
|
}
|
|
|
|
if (validTabIds.length !== input.tabIds.length) {
|
|
const invalidIds = input.tabIds.filter(id => !validTabIds.includes(id));
|
|
console.warn(`[group_tabs] Some tab IDs were invalid and skipped: ${invalidIds.join(', ')}`);
|
|
}
|
|
|
|
// Create the group with the valid tab IDs
|
|
const groupOptions: chrome.tabs.GroupOptions = {
|
|
tabIds: validTabIds
|
|
};
|
|
|
|
if (input.windowId) {
|
|
groupOptions.createProperties = { windowId: input.windowId };
|
|
}
|
|
|
|
// Group the tabs
|
|
const groupId = await chrome.tabs.group(groupOptions);
|
|
|
|
// Update group properties if name or color specified
|
|
const color = input.color || 'blue';
|
|
|
|
// Check if chrome.tabGroups API is available
|
|
if (chrome.tabGroups && chrome.tabGroups.update) {
|
|
const updateProperties: chrome.tabGroups.UpdateProperties = {
|
|
color: color
|
|
};
|
|
|
|
if (input.groupName) {
|
|
updateProperties.title = input.groupName;
|
|
}
|
|
|
|
await chrome.tabGroups.update(groupId, updateProperties);
|
|
} else {
|
|
console.warn('[group_tabs] chrome.tabGroups API not available, cannot set group properties');
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
groupId,
|
|
groupName: input.groupName,
|
|
color,
|
|
tabCount: validTabIds.length,
|
|
message: `Successfully created group${input.groupName ? ` "${input.groupName}"` : ''} with ${validTabIds.length} tab(s)`
|
|
};
|
|
} catch (error) {
|
|
console.error('[group_tabs] Error:', error);
|
|
return {
|
|
success: false,
|
|
color: input.color || 'blue',
|
|
tabCount: 0,
|
|
message: `Error grouping tabs: ${error instanceof Error ? error.message : String(error)}`
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all tabs with their information
|
|
*/
|
|
private async getAllTabs(windowId?: number): Promise<TabInfo[]> {
|
|
const queryOptions: chrome.tabs.QueryInfo = {};
|
|
if (windowId !== undefined) {
|
|
queryOptions.windowId = windowId;
|
|
}
|
|
|
|
// get window id from current tab
|
|
// we should only group tabs on the same window
|
|
const currentTab = await chrome.tabs.getCurrent();
|
|
if (currentTab && windowId === undefined) {
|
|
windowId = currentTab.windowId;
|
|
}
|
|
|
|
const tabs = await chrome.tabs.query(queryOptions);
|
|
|
|
return tabs
|
|
.filter(tab => tab.id !== undefined && tab.url && tab.title)
|
|
.map(tab => ({
|
|
id: tab.id!,
|
|
url: tab.url!,
|
|
title: tab.title!,
|
|
active: tab.active || false,
|
|
windowId: tab.windowId || 0
|
|
}));
|
|
}
|
|
}
|