UNPKG

browser-use-typescript

Version:

A TypeScript-based browser automation framework

148 lines 5.57 kB
import * as fs from 'fs'; import * as path from 'path'; import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages"; /** * Extract JSON from model output, handling both plain JSON and code-block-wrapped JSON. */ export function extractJsonFromModelOutput(content) { try { // If content is wrapped in code blocks, extract just the JSON part if (content.includes('```')) { // Find the JSON content between code blocks content = content.split('```')[1]; // Remove language identifier if present (e.g., 'json\n') if (content.includes('\n')) { content = content.split('\n', 2)[1]; } } // Parse the cleaned content return JSON.parse(content); } catch (e) { console.warn(`Failed to parse model output: ${content} ${e}`); throw new Error('Could not parse response.'); } } /** * Convert input messages to a format that is compatible with the planner model */ export function convertInputMessages(inputMessages, modelName) { if (!modelName) { return inputMessages; } if (modelName === 'deepseek-reasoner' || modelName.includes('deepseek-r1')) { const convertedInputMessages = convertMessagesForNonFunctionCallingModels(inputMessages); const mergedInputMessages = mergeSuccessiveMessages(convertedInputMessages, HumanMessage); return mergeSuccessiveMessages(mergedInputMessages, AIMessage); } return inputMessages; } /** * Convert messages for non-function-calling models */ function convertMessagesForNonFunctionCallingModels(inputMessages) { const outputMessages = []; for (const message of inputMessages) { if (message instanceof HumanMessage || message instanceof SystemMessage) { outputMessages.push(message); } else if (message instanceof ToolMessage) { outputMessages.push(new HumanMessage(message.content)); } else if (message instanceof AIMessage) { // Check if tool_calls is a valid JSON object if (message.tool_calls) { const toolCalls = JSON.stringify(message.tool_calls); outputMessages.push(new AIMessage({ content: toolCalls })); } else { outputMessages.push(message); } } else { throw new Error(`Unknown message type: ${typeof message}`); } } return outputMessages; } /** * Some models like deepseek-reasoner don't allow multiple human messages in a row. * This function merges them into one. */ function mergeSuccessiveMessages(messages, classToMerge) { const mergedMessages = []; let streak = 0; for (const message of messages) { if (message instanceof classToMerge) { streak += 1; if (streak > 1) { // Handle content merging based on content type const lastMessage = mergedMessages[mergedMessages.length - 1]; // Safe handling of message content if (typeof message.content === 'string' && typeof lastMessage.content === 'string') { lastMessage.content += message.content; } else if (Array.isArray(message.content) && Array.isArray(lastMessage.content)) { // Safely handle array type content (more complex) // For now, we'll just append the arrays lastMessage.content = [...lastMessage.content, ...message.content]; } // If content types don't match, we just keep both messages else { mergedMessages.push(message); } } else { mergedMessages.push(message); } } else { mergedMessages.push(message); streak = 0; } } return mergedMessages; } /** * Save conversation history to file. */ export function saveConversation(inputMessages, response, target, encoding = 'utf-8') { // Create folders if not exists const dirname = path.dirname(target); if (dirname) { fs.mkdirSync(dirname, { recursive: true }); } const fileContent = []; // Add messages for (const message of inputMessages) { fileContent.push(` ${message.constructor.name} `); // Handle different content types safely if (typeof message.content === 'string') { try { const content = JSON.parse(message.content); fileContent.push(JSON.stringify(content, null, 2)); } catch (error) { console.error(`Failed to parse message content into JSON: ${message.content} ${error}`); fileContent.push(message.content.trim()); } } else if (Array.isArray(message.content)) { // Handle array content by converting to string representation const contentStr = JSON.stringify(message.content); fileContent.push(contentStr); } fileContent.push(''); } // Add response fileContent.push(' RESPONSE'); fileContent.push(JSON.stringify(response, null, 2)); // Write to file with correct type for encoding fs.writeFileSync(target, fileContent.join('\n'), { encoding }); } /** * Write model response to conversation file */ //# sourceMappingURL=utils.js.map