diff --git a/apps/sim/app/api/tools/stagehand/agent/route.ts b/apps/sim/app/api/tools/stagehand/agent/route.ts index e9a6c7dbca..60341a4d17 100644 --- a/apps/sim/app/api/tools/stagehand/agent/route.ts +++ b/apps/sim/app/api/tools/stagehand/agent/route.ts @@ -496,7 +496,7 @@ export async function POST(request: NextRequest) { verbose: 1, logger: (msg) => logger.info(typeof msg === 'string' ? msg : JSON.stringify(msg)), model: { - modelName: 'claude-sonnet-4-20250514', + modelName: 'anthropic/claude-3-7-sonnet-latest', apiKey: apiKey, }, }) @@ -704,7 +704,14 @@ The system will substitute actual values when these placeholders are used, keepi `.trim() const agent = stagehand.agent({ - model: 'anthropic/claude-sonnet-4-20250514', + model: { + modelName: 'anthropic/claude-3-7-sonnet-latest', + apiKey: apiKey, + }, + executionModel: { + modelName: 'anthropic/claude-3-7-sonnet-latest', + apiKey: apiKey, + }, systemPrompt: `${agentInstructions}\n\n${additionalContext}`, }) @@ -795,6 +802,9 @@ The system will substitute actual values when these placeholders are used, keepi }) let structuredOutput = null + const hasOutputSchema = + outputSchema && typeof outputSchema === 'object' && outputSchema !== null + if (agentResult.message) { try { let jsonContent = agentResult.message @@ -807,33 +817,31 @@ The system will substitute actual values when these placeholders are used, keepi structuredOutput = JSON.parse(jsonContent) logger.info('Successfully parsed structured output from agent response') } catch (parseError) { - logger.error('Failed to parse JSON from agent message', { - error: parseError, - message: agentResult.message, - }) + if (hasOutputSchema) { + logger.warn('Failed to parse JSON from agent message, attempting fallback extraction', { + error: parseError, + }) - if ( - outputSchema && - typeof outputSchema === 'object' && - outputSchema !== null && - stagehand - ) { - try { - logger.info('Attempting to extract structured data using Stagehand extract') - const schemaObj = getSchemaObject(outputSchema) - const zodSchema = ensureZodObject(logger, schemaObj) + if (stagehand) { + try { + logger.info('Attempting to extract structured data using Stagehand extract') + const schemaObj = getSchemaObject(outputSchema) + const zodSchema = ensureZodObject(logger, schemaObj) - structuredOutput = await stagehand.extract( - 'Extract the requested information from this page according to the schema', - zodSchema - ) + structuredOutput = await stagehand.extract( + 'Extract the requested information from this page according to the schema', + zodSchema + ) - logger.info('Successfully extracted structured data as fallback', { - keys: structuredOutput ? Object.keys(structuredOutput) : [], - }) - } catch (extractError) { - logger.error('Fallback extraction also failed', { error: extractError }) + logger.info('Successfully extracted structured data as fallback', { + keys: structuredOutput ? Object.keys(structuredOutput) : [], + }) + } catch (extractError) { + logger.error('Fallback extraction also failed', { error: extractError }) + } } + } else { + logger.info('Agent returned plain text response (no schema provided)') } } } diff --git a/apps/sim/app/api/tools/stagehand/extract/route.ts b/apps/sim/app/api/tools/stagehand/extract/route.ts index 4ef4fd66f8..b7a4148922 100644 --- a/apps/sim/app/api/tools/stagehand/extract/route.ts +++ b/apps/sim/app/api/tools/stagehand/extract/route.ts @@ -86,7 +86,7 @@ export async function POST(request: NextRequest) { verbose: 1, logger: (msg) => logger.info(typeof msg === 'string' ? msg : JSON.stringify(msg)), model: { - modelName: 'gpt-4o', + modelName: 'openai/gpt-4o', apiKey: apiKey, }, }) diff --git a/apps/sim/blocks/blocks/browser_use.ts b/apps/sim/blocks/blocks/browser_use.ts index 79045cdb8f..4698af2cb9 100644 --- a/apps/sim/blocks/blocks/browser_use.ts +++ b/apps/sim/blocks/blocks/browser_use.ts @@ -32,11 +32,23 @@ export const BrowserUseBlock: BlockConfig = { title: 'Model', type: 'dropdown', options: [ - { label: 'gpt-4o', id: 'gpt-4o' }, - { label: 'gemini-2.0-flash', id: 'gemini-2.0-flash' }, - { label: 'gemini-2.0-flash-lite', id: 'gemini-2.0-flash-lite' }, - { label: 'claude-3-7-sonnet-20250219', id: 'claude-3-7-sonnet-20250219' }, - { label: 'llama-4-maverick-17b-128e-instruct', id: 'llama-4-maverick-17b-128e-instruct' }, + { label: 'Browser Use LLM', id: 'browser-use-llm' }, + { label: 'GPT-4o', id: 'gpt-4o' }, + { label: 'GPT-4o Mini', id: 'gpt-4o-mini' }, + { label: 'GPT-4.1', id: 'gpt-4.1' }, + { label: 'GPT-4.1 Mini', id: 'gpt-4.1-mini' }, + { label: 'O3', id: 'o3' }, + { label: 'O4 Mini', id: 'o4-mini' }, + { label: 'Gemini 2.5 Flash', id: 'gemini-2.5-flash' }, + { label: 'Gemini 2.5 Pro', id: 'gemini-2.5-pro' }, + { label: 'Gemini 3 Pro Preview', id: 'gemini-3-pro-preview' }, + { label: 'Gemini Flash Latest', id: 'gemini-flash-latest' }, + { label: 'Gemini Flash Lite Latest', id: 'gemini-flash-lite-latest' }, + { label: 'Claude 3.7 Sonnet', id: 'claude-3-7-sonnet-20250219' }, + { label: 'Claude Sonnet 4', id: 'claude-sonnet-4-20250514' }, + { label: 'Claude Sonnet 4.5', id: 'claude-sonnet-4-5-20250929' }, + { label: 'Claude Opus 4.5', id: 'claude-opus-4-5-20251101' }, + { label: 'Llama 4 Maverick', id: 'llama-4-maverick-17b-128e-instruct' }, ], }, { diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index 20e8063871..e2f3ebaba0 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -79,6 +79,7 @@ const nextConfig: NextConfig = { 'pino', 'pino-pretty', 'thread-stream', + '@browserbasehq/stagehand', ], experimental: { optimizeCss: true, diff --git a/apps/sim/socket-server/handlers/subblocks.ts b/apps/sim/socket-server/handlers/subblocks.ts index ea4e621cde..c7d42f67e6 100644 --- a/apps/sim/socket-server/handlers/subblocks.ts +++ b/apps/sim/socket-server/handlers/subblocks.ts @@ -195,8 +195,6 @@ async function flushSubblockUpdate( sock.emit('operation-confirmed', { operationId: opId, serverTimestamp: Date.now() }) } }) - - logger.debug(`Flushed subblock update ${workflowId}: ${blockId}.${subblockId}`) } else { pending.opToSocket.forEach((socketId, opId) => { const sock = (roomManager as any).io?.sockets?.sockets?.get(socketId)