camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__py3-none-any.whl
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.
- camel/__init__.py +1 -1
- camel/agents/_types.py +6 -2
- camel/agents/_utils.py +38 -0
- camel/agents/chat_agent.py +4014 -410
- camel/agents/mcp_agent.py +30 -27
- camel/agents/repo_agent.py +2 -1
- camel/benchmarks/browsecomp.py +6 -6
- camel/configs/__init__.py +15 -0
- camel/configs/aihubmix_config.py +88 -0
- camel/configs/amd_config.py +70 -0
- camel/configs/cometapi_config.py +104 -0
- camel/configs/minimax_config.py +93 -0
- camel/configs/nebius_config.py +103 -0
- camel/configs/vllm_config.py +2 -0
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/datagen/self_improving_cot.py +1 -1
- camel/datasets/base_generator.py +39 -10
- camel/environments/__init__.py +12 -0
- camel/environments/rlcards_env.py +860 -0
- camel/environments/single_step.py +28 -3
- camel/environments/tic_tac_toe.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker/Dockerfile +4 -16
- camel/interpreters/docker_interpreter.py +3 -2
- camel/interpreters/e2b_interpreter.py +34 -1
- camel/interpreters/internal_python_interpreter.py +51 -2
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/loaders/__init__.py +11 -2
- camel/loaders/base_loader.py +85 -0
- camel/loaders/chunkr_reader.py +9 -0
- camel/loaders/firecrawl_reader.py +4 -4
- camel/logger.py +1 -1
- camel/memories/agent_memories.py +84 -1
- camel/memories/base.py +34 -0
- camel/memories/blocks/chat_history_block.py +122 -4
- camel/memories/blocks/vectordb_block.py +8 -1
- camel/memories/context_creators/score_based.py +29 -237
- camel/memories/records.py +88 -8
- camel/messages/base.py +166 -40
- camel/messages/func_message.py +32 -5
- camel/models/__init__.py +10 -0
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +1 -16
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +117 -18
- camel/models/aws_bedrock_model.py +2 -33
- camel/models/azure_openai_model.py +205 -91
- camel/models/base_audio_model.py +3 -1
- camel/models/base_model.py +189 -24
- camel/models/cohere_model.py +5 -17
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +1 -16
- camel/models/deepseek_model.py +6 -16
- camel/models/fish_audio_model.py +6 -0
- camel/models/gemini_model.py +71 -20
- camel/models/groq_model.py +1 -17
- camel/models/internlm_model.py +1 -16
- camel/models/litellm_model.py +49 -32
- camel/models/lmstudio_model.py +1 -17
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +1 -16
- camel/models/model_factory.py +27 -1
- camel/models/model_manager.py +24 -6
- camel/models/modelscope_model.py +1 -16
- camel/models/moonshot_model.py +185 -19
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +0 -5
- camel/models/netmind_model.py +1 -16
- camel/models/novita_model.py +1 -16
- camel/models/nvidia_model.py +1 -16
- camel/models/ollama_model.py +4 -19
- camel/models/openai_compatible_model.py +171 -46
- camel/models/openai_model.py +205 -77
- camel/models/openrouter_model.py +1 -17
- camel/models/ppio_model.py +1 -16
- camel/models/qianfan_model.py +1 -16
- camel/models/qwen_model.py +1 -16
- camel/models/reka_model.py +1 -16
- camel/models/samba_model.py +34 -47
- camel/models/sglang_model.py +64 -31
- camel/models/siliconflow_model.py +1 -16
- camel/models/stub_model.py +0 -4
- camel/models/togetherai_model.py +1 -16
- camel/models/vllm_model.py +1 -16
- camel/models/volcano_model.py +0 -17
- camel/models/watsonx_model.py +1 -16
- camel/models/yi_model.py +1 -16
- camel/models/zhipuai_model.py +60 -16
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/runtimes/configs.py +11 -11
- camel/runtimes/daytona_runtime.py +15 -16
- camel/runtimes/docker_runtime.py +6 -6
- camel/runtimes/remote_http_runtime.py +5 -5
- camel/services/agent_openapi_server.py +380 -0
- camel/societies/__init__.py +2 -0
- camel/societies/role_playing.py +26 -28
- camel/societies/workforce/__init__.py +2 -0
- camel/societies/workforce/events.py +122 -0
- camel/societies/workforce/prompts.py +249 -38
- camel/societies/workforce/role_playing_worker.py +82 -20
- camel/societies/workforce/single_agent_worker.py +634 -34
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +169 -23
- camel/societies/workforce/utils.py +176 -9
- camel/societies/workforce/worker.py +77 -23
- camel/societies/workforce/workflow_memory_manager.py +772 -0
- camel/societies/workforce/workforce.py +3168 -478
- camel/societies/workforce/workforce_callback.py +74 -0
- camel/societies/workforce/workforce_logger.py +203 -175
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/__init__.py +4 -0
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/key_value_storages/mem0_cloud.py +48 -47
- camel/storages/object_storages/google_cloud.py +1 -1
- camel/storages/vectordb_storages/__init__.py +6 -0
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/oceanbase.py +13 -13
- camel/storages/vectordb_storages/pgvector.py +349 -0
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/storages/vectordb_storages/surreal.py +365 -0
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/tasks/task.py +244 -27
- camel/toolkits/__init__.py +46 -8
- camel/toolkits/aci_toolkit.py +64 -19
- camel/toolkits/arxiv_toolkit.py +6 -6
- camel/toolkits/base.py +63 -5
- camel/toolkits/code_execution.py +28 -1
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/craw4ai_toolkit.py +93 -0
- camel/toolkits/dappier_toolkit.py +10 -6
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
- camel/toolkits/excel_toolkit.py +901 -67
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +30 -6
- camel/toolkits/github_toolkit.py +107 -20
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +38 -4
- camel/toolkits/google_drive_mcp_toolkit.py +54 -0
- camel/toolkits/human_toolkit.py +34 -10
- camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +3749 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +130 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -0
- camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
- camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
- camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +3 -4
- camel/toolkits/klavis_toolkit.py +5 -1
- camel/toolkits/markitdown_toolkit.py +104 -0
- camel/toolkits/math_toolkit.py +64 -10
- camel/toolkits/mcp_toolkit.py +370 -45
- camel/toolkits/memory_toolkit.py +5 -1
- camel/toolkits/message_agent_toolkit.py +608 -0
- camel/toolkits/message_integration.py +724 -0
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/note_taking_toolkit.py +277 -0
- camel/toolkits/notion_mcp_toolkit.py +224 -0
- camel/toolkits/openbb_toolkit.py +5 -1
- camel/toolkits/origene_mcp_toolkit.py +56 -0
- camel/toolkits/playwright_mcp_toolkit.py +12 -31
- camel/toolkits/pptx_toolkit.py +25 -12
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/screenshot_toolkit.py +213 -0
- camel/toolkits/search_toolkit.py +437 -142
- camel/toolkits/slack_toolkit.py +104 -50
- camel/toolkits/sympy_toolkit.py +1 -1
- camel/toolkits/task_planning_toolkit.py +3 -3
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/thinking_toolkit.py +1 -1
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +106 -26
- camel/toolkits/video_download_toolkit.py +17 -14
- camel/toolkits/web_deploy_toolkit.py +1219 -0
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/zapier_toolkit.py +5 -1
- camel/types/__init__.py +2 -2
- camel/types/agents/tool_calling_record.py +4 -1
- camel/types/enums.py +316 -40
- camel/types/openai_types.py +2 -2
- camel/types/unified_model_type.py +31 -4
- camel/utils/commons.py +36 -5
- camel/utils/constants.py +3 -0
- camel/utils/context_utils.py +1003 -0
- camel/utils/mcp.py +138 -4
- camel/utils/mcp_client.py +45 -1
- camel/utils/message_summarizer.py +148 -0
- camel/utils/token_counting.py +43 -20
- camel/utils/tool_result.py +44 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/dalle_toolkit.py +0 -175
- camel/toolkits/file_write_toolkit.py +0 -444
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
const WebSocket = require('ws');
|
|
2
|
+
const { HybridBrowserToolkit } = require('./dist/index.js');
|
|
3
|
+
|
|
4
|
+
class WebSocketBrowserServer {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.toolkit = null;
|
|
7
|
+
this.port = 0; // Let the OS assign a free port
|
|
8
|
+
this.server = null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async start() {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
this.server = new WebSocket.Server({
|
|
14
|
+
port: this.port,
|
|
15
|
+
maxPayload: 50 * 1024 * 1024 // 50MB limit instead of default 1MB
|
|
16
|
+
}, () => {
|
|
17
|
+
this.port = this.server.address().port;
|
|
18
|
+
console.log(`WebSocket server started on port ${this.port}`);
|
|
19
|
+
resolve(this.port);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.server.on('connection', (ws) => {
|
|
23
|
+
console.log('Client connected');
|
|
24
|
+
|
|
25
|
+
ws.on('message', async (message) => {
|
|
26
|
+
try {
|
|
27
|
+
const data = JSON.parse(message.toString());
|
|
28
|
+
const { id, command, params } = data;
|
|
29
|
+
|
|
30
|
+
console.log(`Received command: ${command} with id: ${id}`);
|
|
31
|
+
|
|
32
|
+
const result = await this.handleCommand(command, params);
|
|
33
|
+
|
|
34
|
+
const response = {
|
|
35
|
+
id,
|
|
36
|
+
success: true,
|
|
37
|
+
result
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
ws.send(JSON.stringify(response));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Error handling command:', error);
|
|
43
|
+
|
|
44
|
+
const errorResponse = {
|
|
45
|
+
id: data?.id || 'unknown',
|
|
46
|
+
success: false,
|
|
47
|
+
error: error.message,
|
|
48
|
+
stack: error.stack
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
ws.send(JSON.stringify(errorResponse));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
ws.on('close', (code, reason) => {
|
|
56
|
+
console.log('Client disconnected, code:', code, 'reason:', reason?.toString());
|
|
57
|
+
// Clean up resources when client disconnects
|
|
58
|
+
if (this.toolkit) {
|
|
59
|
+
this.toolkit.closeBrowser().catch(err => {
|
|
60
|
+
console.error('Error closing browser on disconnect:', err);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
ws.on('error', (error) => {
|
|
66
|
+
console.error('WebSocket error:', error);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.server.on('error', (error) => {
|
|
71
|
+
console.error('Server error:', error);
|
|
72
|
+
reject(error);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async handleCommand(command, params) {
|
|
78
|
+
switch (command) {
|
|
79
|
+
case 'init':
|
|
80
|
+
console.log('Initializing toolkit with params:', JSON.stringify(params, null, 2));
|
|
81
|
+
|
|
82
|
+
// Check if CDP is available first
|
|
83
|
+
let useCdp = false;
|
|
84
|
+
let cdpUrl = params.cdpUrl || 'http://localhost:9222';
|
|
85
|
+
|
|
86
|
+
// Extract base URL and port for validation
|
|
87
|
+
const baseUrl = cdpUrl.includes('/devtools/') ? cdpUrl.split('/devtools/')[0] : cdpUrl;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Test if Chrome debug port is accessible and get page URL
|
|
91
|
+
const response = await fetch(`${baseUrl}/json`);
|
|
92
|
+
if (response.ok) {
|
|
93
|
+
const pages = await response.json();
|
|
94
|
+
if (pages && pages.length > 0) {
|
|
95
|
+
// If user provided a specific page URL, use it; otherwise use first available
|
|
96
|
+
if (cdpUrl.includes('/devtools/page/') || cdpUrl.includes('/devtools/browser/')) {
|
|
97
|
+
useCdp = true;
|
|
98
|
+
console.log(`Using provided CDP URL: ${cdpUrl}`);
|
|
99
|
+
} else {
|
|
100
|
+
// Use the first available page
|
|
101
|
+
const firstPage = pages[0];
|
|
102
|
+
const pageUrl = firstPage.devtoolsFrontendUrl;
|
|
103
|
+
const pageId = pageUrl.match(/ws=localhost:\d+(.*)$/)?.[1];
|
|
104
|
+
|
|
105
|
+
if (pageId) {
|
|
106
|
+
useCdp = true;
|
|
107
|
+
cdpUrl = `${baseUrl}${pageId}`;
|
|
108
|
+
console.log(`Chrome debug port detected, using CDP connection to: ${pageId}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.log('Chrome debug port not accessible, will start new browser instance');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const config = {
|
|
118
|
+
connectOverCdp: useCdp,
|
|
119
|
+
cdpUrl: useCdp ? cdpUrl : undefined,
|
|
120
|
+
headless: false,
|
|
121
|
+
...params
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
console.log('Final config:', JSON.stringify(config, null, 2));
|
|
125
|
+
this.toolkit = new HybridBrowserToolkit(config);
|
|
126
|
+
return { message: 'Toolkit initialized with CDP connection' };
|
|
127
|
+
|
|
128
|
+
case 'open_browser':
|
|
129
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
130
|
+
return await this.toolkit.openBrowser(params.startUrl);
|
|
131
|
+
|
|
132
|
+
case 'close_browser':
|
|
133
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
134
|
+
return await this.toolkit.closeBrowser();
|
|
135
|
+
|
|
136
|
+
case 'visit_page':
|
|
137
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
138
|
+
return await this.toolkit.visitPage(params.url);
|
|
139
|
+
|
|
140
|
+
case 'get_page_snapshot':
|
|
141
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
142
|
+
return await this.toolkit.getPageSnapshot(params.viewport_limit);
|
|
143
|
+
|
|
144
|
+
case 'get_snapshot_for_ai': {
|
|
145
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
146
|
+
// Support includeCoordinates and viewportLimit parameters
|
|
147
|
+
const includeCoordinates = Boolean(params.includeCoordinates);
|
|
148
|
+
const viewportLimit = Boolean(params.viewportLimit);
|
|
149
|
+
return await this.toolkit.session.getSnapshotForAI(includeCoordinates, viewportLimit);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
case 'get_som_screenshot': {
|
|
153
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
154
|
+
console.log('Starting screenshot...');
|
|
155
|
+
const startTime = Date.now();
|
|
156
|
+
const result = await this.toolkit.getSomScreenshot();
|
|
157
|
+
const endTime = Date.now();
|
|
158
|
+
console.log(`Screenshot completed in ${endTime - startTime}ms`);
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
case 'click':
|
|
162
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
163
|
+
return await this.toolkit.click(params.ref);
|
|
164
|
+
|
|
165
|
+
case 'type':
|
|
166
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
167
|
+
// Handle both single input and multiple inputs
|
|
168
|
+
if (params.inputs) {
|
|
169
|
+
// Multiple inputs mode - pass inputs array directly
|
|
170
|
+
return await this.toolkit.type(params.inputs);
|
|
171
|
+
} else {
|
|
172
|
+
// Single input mode - pass ref and text
|
|
173
|
+
return await this.toolkit.type(params.ref, params.text);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
case 'select':
|
|
177
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
178
|
+
return await this.toolkit.select(params.ref, params.value);
|
|
179
|
+
|
|
180
|
+
case 'scroll':
|
|
181
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
182
|
+
return await this.toolkit.scroll(params.direction, params.amount);
|
|
183
|
+
|
|
184
|
+
case 'enter':
|
|
185
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
186
|
+
return await this.toolkit.enter();
|
|
187
|
+
|
|
188
|
+
case 'mouse_control':
|
|
189
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
190
|
+
return await this.toolkit.mouseControl(params.control, params.x, params.y);
|
|
191
|
+
|
|
192
|
+
case 'mouse_drag':
|
|
193
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
194
|
+
return await this.toolkit.mouseDrag(params.from_ref, params.to_ref);
|
|
195
|
+
|
|
196
|
+
case 'press_key':
|
|
197
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
198
|
+
return await this.toolkit.pressKeys(params.keys);
|
|
199
|
+
|
|
200
|
+
case 'batch_keyboard_input':
|
|
201
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
202
|
+
const skipStabilityWait = params.skipStabilityWait !== undefined ? params.skipStabilityWait : true;
|
|
203
|
+
return await this.toolkit.batchKeyboardInput(params.operations, skipStabilityWait);
|
|
204
|
+
|
|
205
|
+
case 'back':
|
|
206
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
207
|
+
return await this.toolkit.back();
|
|
208
|
+
|
|
209
|
+
case 'forward':
|
|
210
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
211
|
+
return await this.toolkit.forward();
|
|
212
|
+
|
|
213
|
+
case 'switch_tab':
|
|
214
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
215
|
+
return await this.toolkit.switchTab(params.tabId);
|
|
216
|
+
|
|
217
|
+
case 'close_tab':
|
|
218
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
219
|
+
return await this.toolkit.closeTab(params.tabId);
|
|
220
|
+
|
|
221
|
+
case 'get_tab_info':
|
|
222
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
223
|
+
return await this.toolkit.getTabInfo();
|
|
224
|
+
|
|
225
|
+
case 'console_view':
|
|
226
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
227
|
+
return await this.toolkit.getConsoleView();
|
|
228
|
+
|
|
229
|
+
case 'console_exec':
|
|
230
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
231
|
+
return await this.toolkit.consoleExecute(params.code);
|
|
232
|
+
|
|
233
|
+
case 'wait_user':
|
|
234
|
+
if (!this.toolkit) throw new Error('Toolkit not initialized');
|
|
235
|
+
return await this.toolkit.waitUser(params.timeout);
|
|
236
|
+
|
|
237
|
+
case 'shutdown': {
|
|
238
|
+
console.log('Shutting down server...');
|
|
239
|
+
|
|
240
|
+
// Close browser first
|
|
241
|
+
if (this.toolkit) {
|
|
242
|
+
try {
|
|
243
|
+
await this.toolkit.closeBrowser();
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('Error closing browser:', error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Return response immediately
|
|
250
|
+
const shutdownResponse = { message: 'Server shutting down' };
|
|
251
|
+
|
|
252
|
+
// Schedule server shutdown after a short delay to ensure response is sent
|
|
253
|
+
setTimeout(() => {
|
|
254
|
+
// Close the WebSocket server properly
|
|
255
|
+
if (this.server) {
|
|
256
|
+
this.server.close((err) => {
|
|
257
|
+
if (err) {
|
|
258
|
+
console.error('Error closing server:', err);
|
|
259
|
+
} else {
|
|
260
|
+
console.log('WebSocket server closed successfully');
|
|
261
|
+
}
|
|
262
|
+
console.log('Exiting process...');
|
|
263
|
+
process.exit(0);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Fallback timeout in case server close hangs
|
|
267
|
+
setTimeout(() => {
|
|
268
|
+
console.log('Server close timeout, forcing exit...');
|
|
269
|
+
process.exit(0);
|
|
270
|
+
}, 5000); // 5 second fallback
|
|
271
|
+
} else {
|
|
272
|
+
console.log('No server to close, exiting...');
|
|
273
|
+
process.exit(0);
|
|
274
|
+
}
|
|
275
|
+
}, 100); // Delay to ensure response is sent
|
|
276
|
+
|
|
277
|
+
return shutdownResponse;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
default:
|
|
281
|
+
throw new Error(`Unknown command: ${command}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async stop() {
|
|
286
|
+
if (this.server) {
|
|
287
|
+
this.server.close();
|
|
288
|
+
console.log('WebSocket server stopped');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Start server if this file is run directly
|
|
294
|
+
if (require.main === module) {
|
|
295
|
+
const server = new WebSocketBrowserServer();
|
|
296
|
+
|
|
297
|
+
server.start().then((port) => {
|
|
298
|
+
// Output the port so the Python client can connect
|
|
299
|
+
console.log(`SERVER_READY:${port}`);
|
|
300
|
+
}).catch((error) => {
|
|
301
|
+
console.error('Failed to start server:', error);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Handle graceful shutdown
|
|
306
|
+
process.on('SIGINT', async () => {
|
|
307
|
+
console.log('Received SIGINT, shutting down gracefully...');
|
|
308
|
+
await server.stop();
|
|
309
|
+
process.exit(0);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
process.on('SIGTERM', async () => {
|
|
313
|
+
console.log('Received SIGTERM, shutting down gracefully...');
|
|
314
|
+
await server.stop();
|
|
315
|
+
process.exit(0);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = WebSocketBrowserServer;
|