Repository: microsoft/playwright
File: packages/playwright/src/agents/performTask.ts (TypeScript)

Code before:

import { debug } from 'playwright-core/lib/utilsBundle';
import { z, zodToJsonSchema, Loop } from 'playwright-core/lib/mcpBundle';

import { identityBrowserContextFactory } from '../mcp/browser/browserContextFactory';
import { BrowserServerBackend } from '../mcp/browser/browserServerBackend';
import { defaultConfig } from '../mcp/browser/config';
import { wrapInClient } from '../mcp/sdk/server';

import type * as playwright from 'playwright-core';
import type * as lowireLoop from '@lowire/loop';
import type * as zod from 'zod';
import type { TestInfo } from '../../types/test';

export type PerformTaskOptions = {
  provider?: 'github' | 'openai' | 'anthropic' | 'google';
  model?: string;
  maxTokens?: number;
  reasoning?: boolean;
  temperature?: number;
};

const resultSchema = z.object({
  code: z.string().optional().describe(`
Generated code to perform the task using Playwright API.
Check out the <code> blocks and combine them. Should be presented in a following fork:

perform(async ({ page }) => {
  // generated code here.
});
`),
  error: z.string().optional().describe('The error that occurred if execution failed.').optional(),
});

export async function performTask(testInfo: TestInfo, context: playwright.BrowserContext, userTask: string, options: PerformTaskOptions) {
  const cacheStatus = await performTaskFromCache(testInfo, context, userTask);
  if (cacheStatus === 'success')
    return;

  const backend = new BrowserServerBackend(defaultConfig, identityBrowserContextFactory(context));
  const client = await wrapInClient(backend, { name: 'Internal', version: '0.0.0' });
  const callTool: (params: { name: string, arguments: any}) => Promise<lowireLoop.ToolResult> = async params => {
    return await client.callTool(params) as lowireLoop.ToolResult;
  };

  const loop = new Loop(options.provider ?? 'github', {
    model: options.model ?? 'claude-sonnet-4.5',
    reasoning: options.reasoning,
    temperature: options.temperature,
    maxTokens: options.maxTokens,
    summarize: true,

Review comment (suggestion):
```suggestion
Check out the <code> blocks and combine them. Should be presented in the following form:
```

Code after:

import { debug } from 'playwright-core/lib/utilsBundle';
import { z, zodToJsonSchema, Loop } from 'playwright-core/lib/mcpBundle';

import { identityBrowserContextFactory } from '../mcp/browser/browserContextFactory';
import { BrowserServerBackend } from '../mcp/browser/browserServerBackend';
import { defaultConfig } from '../mcp/browser/config';
import { wrapInClient } from '../mcp/sdk/server';

import type * as playwright from 'playwright-core';
import type * as lowireLoop from '@lowire/loop';
import type * as zod from 'zod';
import type { TestInfo } from '../../types/test';

export type PerformTaskOptions = {
  provider?: 'github' | 'openai' | 'anthropic' | 'google';
  model?: string;
  maxTokens?: number;
  reasoning?: boolean;
  temperature?: number;
};

const resultSchema = z.object({
  code: z.string().optional().describe(`
Generated code to perform the task using Playwright API.
Check out the <code> blocks and combine them. Should be presented in the following form:

perform(async ({ page }) => {
  // generated code here.
});
`),
  error: z.string().optional().describe('The error that occurred if execution failed.').optional(),
});

export async function performTask(testInfo: TestInfo, context: playwright.BrowserContext, userTask: string, options: PerformTaskOptions) {
  const cacheStatus = await performTaskFromCache(testInfo, context, userTask);
  if (cacheStatus === 'success')
    return;

  const backend = new BrowserServerBackend(defaultConfig, identityBrowserContextFactory(context));
  const client = await wrapInClient(backend, { name: 'Internal', version: '0.0.0' });
  const callTool: (params: { name: string, arguments: any}) => Promise<lowireLoop.ToolResult> = async params => {
    return await client.callTool(params) as lowireLoop.ToolResult;
  };

  const loop = new Loop(options.provider ?? 'github', {
    model: options.model ?? 'claude-sonnet-4.5',
    reasoning: options.reasoning,
    temperature: options.temperature,
    maxTokens: options.maxTokens,
    summarize: true,