grasp-sdk 0.1.6__tar.gz → 0.1.7__tar.gz

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.

Potentially problematic release.


This version of grasp-sdk might be problematic. Click here for more details.

Files changed (30) hide show
  1. {grasp_sdk-0.1.6/grasp_sdk.egg-info → grasp_sdk-0.1.7}/PKG-INFO +1 -1
  2. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/__init__.py +2 -7
  3. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/models/__init__.py +0 -2
  4. grasp_sdk-0.1.7/grasp_sdk/sandbox/http-proxy.mjs +322 -0
  5. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/services/browser.py +14 -14
  6. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/services/sandbox.py +3 -3
  7. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/utils/config.py +0 -4
  8. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7/grasp_sdk.egg-info}/PKG-INFO +1 -1
  9. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/SOURCES.txt +1 -0
  10. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/pyproject.toml +1 -1
  11. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/MANIFEST.in +0 -0
  12. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/README.md +0 -0
  13. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/build_and_publish.py +0 -0
  14. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/example_usage.py +0 -0
  15. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/sandbox/chrome-stable.mjs +0 -0
  16. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/sandbox/chromium.mjs +0 -0
  17. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/services/__init__.py +0 -0
  18. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/utils/__init__.py +0 -0
  19. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/utils/auth.py +0 -0
  20. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk/utils/logger.py +0 -0
  21. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/dependency_links.txt +0 -0
  22. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/entry_points.txt +0 -0
  23. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/not-zip-safe +0 -0
  24. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/requires.txt +0 -0
  25. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/grasp_sdk.egg-info/top_level.txt +0 -0
  26. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/py.typed +0 -0
  27. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/requirements.txt +0 -0
  28. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/setup.cfg +0 -0
  29. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/setup.py +0 -0
  30. {grasp_sdk-0.1.6 → grasp_sdk-0.1.7}/test_install.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grasp_sdk
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Python SDK for Grasp E2B - Browser automation and sandbox management
5
5
  Home-page: https://github.com/grasp-team/grasp-e2b
6
6
  Author: Grasp Team
@@ -24,7 +24,7 @@ from .models import (
24
24
  SandboxStatus,
25
25
  )
26
26
 
27
- __version__ = "0.1.6"
27
+ __version__ = "0.1.7"
28
28
  __author__ = "Grasp Team"
29
29
  __email__ = "team@grasp.dev"
30
30
 
@@ -76,9 +76,7 @@ class GraspServer:
76
76
 
77
77
  self.browser_service: Optional[BrowserService] = None
78
78
 
79
- self.logger.info(
80
- f'GraspE2B initialized (templateId: {config["sandbox"]["templateId"]})'
81
- )
79
+ self.logger.info('GraspE2B initialized')
82
80
 
83
81
  async def __aenter__(self):
84
82
  connection = await self.create_browser_task()
@@ -147,7 +145,6 @@ class GraspServer:
147
145
 
148
146
  # Create base browser config
149
147
  browser_config: IBrowserConfig = {
150
- 'cdpPort': 9222,
151
148
  'headless': True,
152
149
  'launchTimeout': 30000,
153
150
  'args': [
@@ -158,8 +155,6 @@ class GraspServer:
158
155
  }
159
156
 
160
157
  # Apply user config overrides with type safety
161
- if 'cdpPort' in config:
162
- browser_config['cdpPort'] = config['cdpPort']
163
158
  if 'headless' in config:
164
159
  browser_config['headless'] = config['headless']
165
160
  if 'launchTimeout' in config:
@@ -20,7 +20,6 @@ class SandboxStatus(Enum):
20
20
  class ISandboxConfig(TypedDict):
21
21
  """Sandbox configuration interface."""
22
22
  key: str # Required: Grasp API key
23
- templateId: str # Required: Sandbox template ID
24
23
  timeout: int # Required: Default timeout in milliseconds
25
24
  workspace: NotRequired[str] # Optional: Grasp workspace ID
26
25
  debug: NotRequired[bool] # Optional: Enable debug mode for detailed logging
@@ -28,7 +27,6 @@ class ISandboxConfig(TypedDict):
28
27
 
29
28
  class IBrowserConfig(TypedDict):
30
29
  """Browser service configuration interface."""
31
- cdpPort: int # Required: Port for CDP server (default: 9222)
32
30
  args: List[str] # Required: Chromium launch arguments
33
31
  headless: bool # Required: Headless mode (default: true)
34
32
  launchTimeout: int # Required: Timeout for browser launch (default: 30000ms)
@@ -0,0 +1,322 @@
1
+ import httpProxy from 'http-proxy';
2
+ import http from 'http';
3
+
4
+ import { Logtail } from '@logtail/node';
5
+ import * as Sentry from "@sentry/node";
6
+
7
+ const logtail = new Logtail(process.env.BS_SOURCE_TOKEN, {
8
+ endpoint: `https://${process.env.BS_INGESTING_HOST}`,
9
+ });
10
+
11
+ Sentry.init({
12
+ dsn: process.env.SENTRY_DSN,
13
+
14
+ // Setting this option to true will send default PII data to Sentry.
15
+ // For example, automatic IP address collection on events
16
+ sendDefaultPii: true,
17
+ _experiments: {
18
+ enableLogs: true, // 启用日志功能
19
+ },
20
+ });
21
+
22
+ const logger = {
23
+ info: async (message, context) => {
24
+ Sentry.logger.info(message, context);
25
+ return logtail.info(message, context);
26
+ },
27
+ warn: async (message, context) => {
28
+ Sentry.logger.warn(message, context);
29
+ return logtail.warn(message, context);
30
+ },
31
+ error: async (message, context) => {
32
+ Sentry.logger.error(message, context);
33
+ return logtail.error(message, context);
34
+ },
35
+ }
36
+
37
+ function parseWebSocketFrame(buffer) {
38
+ if (buffer.length < 2) {
39
+ throw new Error('Incomplete WebSocket frame.');
40
+ }
41
+
42
+ const firstByte = buffer.readUInt8(0);
43
+ const fin = (firstByte & 0x80) !== 0;
44
+ const opcode = firstByte & 0x0f;
45
+
46
+ // 仅处理文本帧(opcode 为 0x1)
47
+ if (opcode !== 0x1) {
48
+ throw new Error(`Unsupported opcode: ${opcode}`);
49
+ }
50
+
51
+ const secondByte = buffer.readUInt8(1);
52
+ const isMasked = (secondByte & 0x80) !== 0;
53
+ let payloadLength = secondByte & 0x7f;
54
+ let offset = 2;
55
+
56
+ if (payloadLength === 126) {
57
+ if (buffer.length < offset + 2) {
58
+ throw new Error('Incomplete extended payload length.');
59
+ }
60
+ payloadLength = buffer.readUInt16BE(offset);
61
+ offset += 2;
62
+ } else if (payloadLength === 127) {
63
+ if (buffer.length < offset + 8) {
64
+ throw new Error('Incomplete extended payload length.');
65
+ }
66
+ // 注意:JavaScript 无法精确表示超过 2^53 的整数
67
+ const highBits = buffer.readUInt32BE(offset);
68
+ const lowBits = buffer.readUInt32BE(offset + 4);
69
+ payloadLength = highBits * 2 ** 32 + lowBits;
70
+ offset += 8;
71
+ }
72
+
73
+ let maskingKey;
74
+ if (isMasked) {
75
+ if (buffer.length < offset + 4) {
76
+ throw new Error('Incomplete masking key.');
77
+ }
78
+ maskingKey = buffer.slice(offset, offset + 4);
79
+ offset += 4;
80
+ }
81
+
82
+ if (buffer.length < offset + payloadLength) {
83
+ throw new Error('Incomplete payload data.');
84
+ }
85
+
86
+ const payloadData = buffer.slice(offset, offset + payloadLength);
87
+
88
+ if (isMasked) {
89
+ for (let i = 0; i < payloadLength; i++) {
90
+ payloadData[i] ^= maskingKey[i % 4];
91
+ }
92
+ }
93
+
94
+ return payloadData.toString('utf8');
95
+ }
96
+
97
+ const sandboxId = process.env.SANDBOX_ID;
98
+ const cdpPort = Number(process.env.CDP_PORT);
99
+ const headless = process.env.HEADLESS !== 'false';
100
+ const enableAdblock = process.env.ADBLOCK !== 'false';
101
+ const timeoutMS = process.env.SANBOX_TIMEOUT;
102
+ const workspace = process.env.WORKSPACE;
103
+ const keepAliveMS = Number(process.env.KEEP_ALIVE_MS) || 0;
104
+ const args = [];
105
+
106
+ try {
107
+ // 创建代理服务:从 ${this.config.cdpPort! + 1} 转发到 127.0.0.1:${this.config.cdpPort!}
108
+ const proxy = httpProxy.createProxyServer({
109
+ target: `http://127.0.0.1:${cdpPort}`,
110
+ ws: true, // 支持 WebSocket
111
+ changeOrigin: true
112
+ });
113
+
114
+ const clients = new Set();
115
+
116
+ // 监听 WebSocket 事件
117
+ proxy.on('open', () => {
118
+ console.log('🔌 CDP WebSocket connection established');
119
+ const wsId = Date.now();
120
+ logger.info('CDP WebSocket connection established', { sandboxId, wsId });
121
+ Sentry.addBreadcrumb({
122
+ category: 'websocket',
123
+ message: 'CDP connection established',
124
+ level: 'info',
125
+ data: { sandboxId }
126
+ });
127
+
128
+ clients.add(wsId);
129
+ proxy.once('close', async (req, socket, head) => {
130
+ console.log('🔒 CDP WebSocket connection closed');
131
+ await logger.info('CDP WebSocket connection closed', { sandboxId });
132
+ Sentry.addBreadcrumb({
133
+ category: 'websocket',
134
+ message: 'CDP connection closed',
135
+ level: 'info',
136
+ data: { sandboxId }
137
+ });
138
+ clients.delete(wsId);
139
+
140
+ if(clients.size <= 0) {
141
+ setTimeout(() => {
142
+ if(clients.size <= 0) {
143
+ console.log('❌ Force closed...', wsId);
144
+ process.exit(0);
145
+ }
146
+ }, keepAliveMS);
147
+ }
148
+ });
149
+ });
150
+
151
+ proxy.on('proxyReqWs', (proxyReq, req, socket, options, head) => {
152
+ console.log('📡 New CDP WebSocket connection request:', req.url);
153
+ logger.info('New CDP WebSocket connection request', { url: req.url, sandboxId });
154
+ Sentry.addBreadcrumb({
155
+ category: 'websocket',
156
+ message: 'New CDP connection request',
157
+ level: 'info',
158
+ data: { url: req.url, sandboxId }
159
+ });
160
+ });
161
+
162
+ proxy.on('error', (err, req, res) => {
163
+ console.error('❌ CDP WebSocket proxy error:', err);
164
+ logger.error('CDP WebSocket proxy error', { error: err.message, url: req?.url, sandboxId });
165
+ Sentry.captureException(err, {
166
+ tags: { type: 'websocket_proxy_error', sandboxId },
167
+ extra: { url: req?.url }
168
+ });
169
+ });
170
+
171
+ const server = http.createServer(async (req, res) => {
172
+ if (req.url === '/health') {
173
+ res.end('ok');
174
+ return;
175
+ }
176
+ if (req.url === '/json/version' || req.url === '/json/version/') {
177
+ try {
178
+ // 向本地 CDP 发请求,获取原始 JSON
179
+ const jsonRes = await fetch(`http://127.0.0.1:${cdpPort}/json/version`);
180
+ const data = await jsonRes.json();
181
+ // 替换掉本地的 WebSocket 地址为代理暴露地址
182
+ data.webSocketDebuggerUrl = data.webSocketDebuggerUrl.replace(
183
+ `ws://127.0.0.1:${cdpPort}`,
184
+ `wss://${req.headers.host}`
185
+ );
186
+ await logger.info('CDP version info requested', { url: req.url, response: data, sandboxId });
187
+ Sentry.addBreadcrumb({
188
+ category: 'http',
189
+ message: 'CDP version info requested',
190
+ level: 'info',
191
+ data: { url: req.url, response: data, sandboxId }
192
+ });
193
+ res.writeHead(200, { 'Content-Type': 'application/json' });
194
+ res.end(JSON.stringify(data));
195
+ } catch(ex) {
196
+ console.error('Failed to fetch CDP version:', ex.message);
197
+ await logger.error('Failed to fetch CDP version', { error: ex.message, sandboxId });
198
+ Sentry.captureException(ex, {
199
+ tags: { type: 'cdp_version_error', sandboxId }
200
+ });
201
+ res.writeHead(500);
202
+ res.end('Internal Server Error');
203
+ }
204
+ } else {
205
+ proxy.web(req, res, {}, async (err) => {
206
+ console.error('Proxy error:', err);
207
+ await logger.error('HTTP proxy error', { error: err.message, url: req.url, sandboxId });
208
+ Sentry.captureException(err, {
209
+ tags: { type: 'proxy_error', sandboxId },
210
+ extra: { url: req.url }
211
+ });
212
+ res.writeHead(502);
213
+ res.end('Bad gateway');
214
+ });
215
+ }
216
+ });
217
+
218
+ server.on('upgrade', (req, socket, head) => {
219
+ // 监听 WebSocket 数据
220
+ let _buffers = [];
221
+ socket.on('data', (data) => {
222
+ let message = '';
223
+ try {
224
+ _buffers.push(data);
225
+ // console.log(`💬 ${_buffers.length}`);
226
+ message = parseWebSocketFrame(Buffer.concat(_buffers)); // 复制data不能破坏原始数据
227
+ _buffers.length = 0;
228
+ if (message.startsWith('{')){ // 只解析 JSON 消息
229
+ const parsed = JSON.parse(message);
230
+ console.log('📨 CDP WebSocket message:', parsed);
231
+ logger.info('CDP WebSocket message received', {
232
+ data: parsed,
233
+ sandboxId: process.env.SANDBOX_ID,
234
+ });
235
+ Sentry.addBreadcrumb({
236
+ category: 'websocket',
237
+ message: 'CDP message received',
238
+ level: 'debug',
239
+ data: { ...parsed, sandboxId }
240
+ });
241
+ }
242
+ } catch (err) {
243
+ const msg = err.message;
244
+ if(!msg.includes('Incomplete')) {
245
+ // 记录解析错误
246
+ console.warn('⚠️ Failed to parse CDP WebSocket message:', err.message, _buffers.length);
247
+ _buffers.length = 0;
248
+ Sentry.captureException(err, {
249
+ tags: { type: 'websocket_error', sandboxId }
250
+ });
251
+ logger.warn('Failed to parse CDP WebSocket message', {
252
+ error: err.message,
253
+ data: message,
254
+ sandboxId: process.env.SANDBOX_ID
255
+ });
256
+ }
257
+ }
258
+ });
259
+
260
+ socket.on('error', (err) => {
261
+ console.error('❌ CDP WebSocket error:', err);
262
+ logger.error('CDP WebSocket error', { error: err.message, sandboxId });
263
+ Sentry.captureException(err, {
264
+ tags: { type: 'websocket_error', sandboxId }
265
+ });
266
+ });
267
+
268
+ proxy.ws(req, socket, head);
269
+ });
270
+
271
+ server.listen(cdpPort + 1, '0.0.0.0', () => {
272
+ console.log(`🎯 Proxy server listening on http://0.0.0.0:${cdpPort + 1} → http://127.0.0.1:${cdpPort}`);
273
+ logger.info('Proxy server started', {
274
+ port: cdpPort + 1,
275
+ target: cdpPort,
276
+ sandboxId,
277
+ settings: {
278
+ type: 'chromium',
279
+ args,
280
+ headless,
281
+ enableAdblock,
282
+ timeoutMS,
283
+ workspace,
284
+ sandboxId
285
+ },
286
+ });
287
+ Sentry.addBreadcrumb({
288
+ category: 'server',
289
+ message: 'Proxy server started',
290
+ level: 'info',
291
+ data: {
292
+ port: cdpPort + 1,
293
+ target: cdpPort,
294
+ sandboxId,
295
+ settings: {
296
+ type: 'chromium',
297
+ args,
298
+ headless,
299
+ enableAdblock,
300
+ timeoutMS,
301
+ workspace,
302
+ sandboxId
303
+ },
304
+ }
305
+ });
306
+ });
307
+ } catch (ex) {
308
+ console.error('Failed to launch Chromium:', ex);
309
+ logger.error('Failed to launch Chrome', {
310
+ error: ex.message,
311
+ args,
312
+ headless,
313
+ cdpPort,
314
+ enableAdblock,
315
+ sandboxId,
316
+ });
317
+ Sentry.captureException(ex, {
318
+ tags: { type: 'launch_error', sandboxId },
319
+ extra: { args, headless, cdpPort, enableAdblock }
320
+ });
321
+ process.exit(1);
322
+ }
@@ -63,7 +63,6 @@ class BrowserService:
63
63
 
64
64
  # Set default browser config
65
65
  default_config: IBrowserConfig = {
66
- 'cdpPort': 9222,
67
66
  'headless': True,
68
67
  'launchTimeout': 30000,
69
68
  'args': [],
@@ -99,7 +98,7 @@ class BrowserService:
99
98
  Promise that resolves when sandbox is ready
100
99
  """
101
100
  self.logger.info('Initializing Browser service')
102
- await self.sandbox_service.create_sandbox()
101
+ await self.sandbox_service.create_sandbox('grasp-run-template')
103
102
  self.logger.info('Grasp sandbox initialized successfully')
104
103
 
105
104
  async def launch_browser(
@@ -122,8 +121,8 @@ class BrowserService:
122
121
 
123
122
  try:
124
123
  self.logger.info(
125
- f'Launching Chromium browser with CDP (port: {self.config["cdpPort"]}, headless: {self.config["headless"]})'
126
- )
124
+ f'Launching Chromium browser with CDP (port: 9222, headless: {self.config["headless"]})')
125
+
127
126
 
128
127
  # Check if adblock is enabled and adjust browser type
129
128
  if (
@@ -136,7 +135,7 @@ class BrowserService:
136
135
  browser_type = 'chrome-stable'
137
136
 
138
137
  # Read the Playwright script
139
- script_path = Path(__file__).parent.parent / 'sandbox' / f'{browser_type}.mjs'
138
+ script_path = Path(__file__).parent.parent / 'sandbox' / 'http-proxy.mjs'
140
139
 
141
140
  try:
142
141
  with open(script_path, 'r', encoding='utf-8') as f:
@@ -146,7 +145,7 @@ class BrowserService:
146
145
 
147
146
  # Prepare environment variables
148
147
  envs = {
149
- 'CDP_PORT': str(self.config['cdpPort']),
148
+ 'CDP_PORT': '9222',
150
149
  'BROWSER_ARGS': json.dumps(self.config['args']),
151
150
  'LAUNCH_TIMEOUT': str(self.config['launchTimeout']),
152
151
  'SANDBOX_TIMEOUT': str(self.sandbox_service.timeout),
@@ -187,7 +186,7 @@ class BrowserService:
187
186
  self.cdp_connection = result
188
187
 
189
188
  self.logger.info(
190
- f'Chromium browser launched successfully (cdpPort: {self.config["cdpPort"]}, wsUrl: {self.cdp_connection.ws_url})'
189
+ f'Chromium browser launched successfully (cdpPort: 9222, wsUrl: {self.cdp_connection.ws_url})'
191
190
  )
192
191
 
193
192
  # Start health check if not in debug mode
@@ -238,7 +237,7 @@ class BrowserService:
238
237
  Raises:
239
238
  RuntimeError: If CDP server fails to become ready within timeout
240
239
  """
241
- delay_ms = 200
240
+ delay_ms = 100
242
241
  max_attempts = self.config['launchTimeout'] // delay_ms
243
242
 
244
243
  for attempt in range(1, max_attempts + 1):
@@ -246,6 +245,10 @@ class BrowserService:
246
245
  self.logger.debug(
247
246
  f'Checking CDP availability (attempt {attempt}/{max_attempts})'
248
247
  )
248
+
249
+ host = self.sandbox_service.get_sandbox_host(
250
+ 9223
251
+ )
249
252
 
250
253
  # Check if CDP endpoint is responding
251
254
  options: ICommandOptions = {
@@ -253,7 +256,7 @@ class BrowserService:
253
256
  'inBackground': False
254
257
  }
255
258
  result = await self.sandbox_service.run_command(
256
- f'curl -s http://localhost:{self.config["cdpPort"]}/json/version',
259
+ f'curl -s https://{host}/json/version',
257
260
  options,
258
261
  True,
259
262
  )
@@ -264,15 +267,12 @@ class BrowserService:
264
267
  ):
265
268
  stdout_content = getattr(result, 'stdout', '')
266
269
  metadata = json.loads(stdout_content)
267
- host = self.sandbox_service.get_sandbox_host(
268
- self.config['cdpPort'] + 1
269
- )
270
270
 
271
271
  # Update URLs for external access
272
272
  ws_url = metadata['webSocketDebuggerUrl'].replace(
273
273
  'ws://', 'wss://'
274
274
  ).replace(
275
- f'localhost:{self.config["cdpPort"]}', host
275
+ f'localhost:9222', host
276
276
  )
277
277
 
278
278
  http_url = f'https://{host}'
@@ -280,7 +280,7 @@ class BrowserService:
280
280
  connection = CDPConnection(
281
281
  ws_url=ws_url,
282
282
  http_url=http_url,
283
- port=self.config['cdpPort']
283
+ port=9222
284
284
  )
285
285
 
286
286
  self.logger.info(f'CDP server is ready (metadata: {metadata})')
@@ -123,7 +123,7 @@ class SandboxService:
123
123
  """Get timeout value."""
124
124
  return self.config['timeout']
125
125
 
126
- async def create_sandbox(self) -> None:
126
+ async def create_sandbox(self, template_id: str) -> None:
127
127
  """
128
128
  Creates and starts a new sandbox.
129
129
 
@@ -143,11 +143,11 @@ class SandboxService:
143
143
 
144
144
  # Create sandbox
145
145
  self.logger.info('Creating Grasp sandbox', {
146
- 'templateId': self.config['templateId'],
146
+ 'templateId': template_id,
147
147
  })
148
148
  # Use Sandbox constructor directly (e2b SDK 1.5.3+)
149
149
  self.sandbox = await AsyncSandbox.create(
150
- template=self.config['templateId'],
150
+ template=template_id,
151
151
  api_key=api_key,
152
152
  timeout=self.config['timeout'] // 1000 # Convert ms to seconds
153
153
  )
@@ -23,7 +23,6 @@ def get_config() -> Dict[str, Any]:
23
23
  return {
24
24
  'sandbox': {
25
25
  'key': os.getenv('GRASP_KEY', ''),
26
- 'templateId': 'playwright-pnpm-template',
27
26
  'timeout': int(os.getenv('GRASP_SERVICE_TIMEOUT', '900000')),
28
27
  'debug': os.getenv('GRASP_DEBUG', 'false').lower() == 'true',
29
28
  },
@@ -44,7 +43,6 @@ def get_sandbox_config() -> ISandboxConfig:
44
43
  config = get_config()
45
44
  sandbox_config = ISandboxConfig(
46
45
  key=config['sandbox']['key'],
47
- templateId=config['sandbox']['templateId'],
48
46
  timeout=config['sandbox']['timeout'],
49
47
  debug=config['sandbox'].get('debug', False),
50
48
  )
@@ -64,7 +62,6 @@ def get_browser_config() -> IBrowserConfig:
64
62
  IBrowserConfig: Browser configuration object.
65
63
  """
66
64
  return IBrowserConfig(
67
- cdpPort=int(os.getenv('GRASP_CDP_PORT', '9222')),
68
65
  args=[
69
66
  '--no-sandbox',
70
67
  '--disable-setuid-sandbox',
@@ -102,7 +99,6 @@ ENV_VARS = {
102
99
  'GRASP_DEBUG': 'GRASP_DEBUG',
103
100
  'GRASP_LOG_LEVEL': 'GRASP_LOG_LEVEL',
104
101
  'GRASP_LOG_FILE': 'GRASP_LOG_FILE',
105
- 'GRASP_CDP_PORT': 'GRASP_CDP_PORT',
106
102
  'GRASP_HEADLESS': 'GRASP_HEADLESS',
107
103
  'GRASP_LAUNCH_TIMEOUT': 'GRASP_LAUNCH_TIMEOUT',
108
104
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grasp_sdk
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Python SDK for Grasp E2B - Browser automation and sandbox management
5
5
  Home-page: https://github.com/grasp-team/grasp-e2b
6
6
  Author: Grasp Team
@@ -32,6 +32,7 @@ grasp_sdk.egg-info/top_level.txt
32
32
  grasp_sdk/models/__init__.py
33
33
  grasp_sdk/sandbox/chrome-stable.mjs
34
34
  grasp_sdk/sandbox/chromium.mjs
35
+ grasp_sdk/sandbox/http-proxy.mjs
35
36
  grasp_sdk/services/__init__.py
36
37
  grasp_sdk/services/browser.py
37
38
  grasp_sdk/services/sandbox.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "grasp_sdk"
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  authors = [
9
9
  {name = "Grasp Team", email = "team@grasp.com"},
10
10
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes