|
1 | 1 | import { z } from 'zod'; |
2 | 2 | import type { AgentRuntime } from '../agent-runtime'; |
3 | 3 | import type { ActionResult, Snapshot, EvaluateJsResult } from '../types'; |
4 | | -import { ToolContext } from './context'; |
| 4 | +import { ToolContext, UnsupportedCapabilityError } from './context'; |
5 | 5 | import { defineTool, ToolRegistry } from './registry'; |
6 | 6 |
|
7 | 7 | const snapshotSchema = z |
@@ -83,6 +83,19 @@ const evaluateJsInput = z.object({ |
83 | 83 | truncate: z.boolean().default(true), |
84 | 84 | }); |
85 | 85 |
|
| 86 | +const grantPermissionsInput = z.object({ |
| 87 | + permissions: z.array(z.string()).min(1), |
| 88 | + origin: z.string().optional(), |
| 89 | +}); |
| 90 | + |
| 91 | +const clearPermissionsInput = z.object({}); |
| 92 | + |
| 93 | +const setGeolocationInput = z.object({ |
| 94 | + latitude: z.number(), |
| 95 | + longitude: z.number(), |
| 96 | + accuracy: z.number().optional(), |
| 97 | +}); |
| 98 | + |
86 | 99 | function getRuntime(ctx: ToolContext | null, runtime?: ToolContext | AgentRuntime): AgentRuntime { |
87 | 100 | if (ctx) return ctx.runtime; |
88 | 101 | if (runtime instanceof ToolContext) return runtime.runtime; |
@@ -342,5 +355,87 @@ export function registerDefaultTools( |
342 | 355 | }) |
343 | 356 | ); |
344 | 357 |
|
| 358 | + registry.register( |
| 359 | + defineTool<z.infer<typeof grantPermissionsInput>, ActionResult, ToolContext | null>({ |
| 360 | + name: 'grant_permissions', |
| 361 | + description: 'Grant browser permissions for the current context.', |
| 362 | + input: grantPermissionsInput, |
| 363 | + output: actionResultSchema, |
| 364 | + handler: async (ctx, params): Promise<ActionResult> => { |
| 365 | + const runtimeRef = getRuntime(ctx, runtime); |
| 366 | + if (ctx) { |
| 367 | + ctx.require('permissions'); |
| 368 | + } else if (!runtimeRef.can('permissions')) { |
| 369 | + throw new UnsupportedCapabilityError('permissions'); |
| 370 | + } |
| 371 | + const context = |
| 372 | + typeof (runtimeRef.page as any)?.context === 'function' |
| 373 | + ? (runtimeRef.page as any).context() |
| 374 | + : null; |
| 375 | + if (!context) { |
| 376 | + throw new Error('Permission context unavailable'); |
| 377 | + } |
| 378 | + await context.grantPermissions(params.permissions, params.origin); |
| 379 | + return { success: true, duration_ms: 0, outcome: 'dom_updated' }; |
| 380 | + }, |
| 381 | + }) |
| 382 | + ); |
| 383 | + |
| 384 | + registry.register( |
| 385 | + defineTool<z.infer<typeof clearPermissionsInput>, ActionResult, ToolContext | null>({ |
| 386 | + name: 'clear_permissions', |
| 387 | + description: 'Clear browser permissions for the current context.', |
| 388 | + input: clearPermissionsInput, |
| 389 | + output: actionResultSchema, |
| 390 | + handler: async (ctx): Promise<ActionResult> => { |
| 391 | + const runtimeRef = getRuntime(ctx, runtime); |
| 392 | + if (ctx) { |
| 393 | + ctx.require('permissions'); |
| 394 | + } else if (!runtimeRef.can('permissions')) { |
| 395 | + throw new UnsupportedCapabilityError('permissions'); |
| 396 | + } |
| 397 | + const context = |
| 398 | + typeof (runtimeRef.page as any)?.context === 'function' |
| 399 | + ? (runtimeRef.page as any).context() |
| 400 | + : null; |
| 401 | + if (!context) { |
| 402 | + throw new Error('Permission context unavailable'); |
| 403 | + } |
| 404 | + await context.clearPermissions(); |
| 405 | + return { success: true, duration_ms: 0, outcome: 'dom_updated' }; |
| 406 | + }, |
| 407 | + }) |
| 408 | + ); |
| 409 | + |
| 410 | + registry.register( |
| 411 | + defineTool<z.infer<typeof setGeolocationInput>, ActionResult, ToolContext | null>({ |
| 412 | + name: 'set_geolocation', |
| 413 | + description: 'Set geolocation for the current browser context.', |
| 414 | + input: setGeolocationInput, |
| 415 | + output: actionResultSchema, |
| 416 | + handler: async (ctx, params): Promise<ActionResult> => { |
| 417 | + const runtimeRef = getRuntime(ctx, runtime); |
| 418 | + if (ctx) { |
| 419 | + ctx.require('permissions'); |
| 420 | + } else if (!runtimeRef.can('permissions')) { |
| 421 | + throw new UnsupportedCapabilityError('permissions'); |
| 422 | + } |
| 423 | + const context = |
| 424 | + typeof (runtimeRef.page as any)?.context === 'function' |
| 425 | + ? (runtimeRef.page as any).context() |
| 426 | + : null; |
| 427 | + if (!context) { |
| 428 | + throw new Error('Permission context unavailable'); |
| 429 | + } |
| 430 | + await context.setGeolocation({ |
| 431 | + latitude: params.latitude, |
| 432 | + longitude: params.longitude, |
| 433 | + accuracy: params.accuracy, |
| 434 | + }); |
| 435 | + return { success: true, duration_ms: 0, outcome: 'dom_updated' }; |
| 436 | + }, |
| 437 | + }) |
| 438 | + ); |
| 439 | + |
345 | 440 | return registry; |
346 | 441 | } |
0 commit comments