UNPKG

@craftapit/tester

Version:

A focused, LLM-powered testing framework for natural language test scenarios

177 lines (168 loc) 6.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CraftacoderAdapter = void 0; const BaseAdapter_1 = require("./BaseAdapter"); class CraftacoderAdapter extends BaseAdapter_1.BaseAdapter { constructor(config) { super(config); this.apiKey = config.apiKey || process.env.CRAFTACODER_API_KEY || ''; this.baseUrl = config.baseUrl || 'http://localhost:3000'; this.model = config.model || 'claude-3-sonnet-20240229'; this.provider = config.provider || 'anthropic'; } async initialize() { console.log('Initializing Craftacoder adapter'); if (!this.apiKey) { throw new Error('Craftacoder API key is required'); } } async cleanup() { console.log('Cleaning up Craftacoder adapter'); // Nothing to clean up } /** * Complete a prompt with the LLM via Craftacoder API * @param prompt The prompt to complete * @returns The completion text */ async complete(prompt) { console.log(`Completing prompt via Craftacoder: ${prompt.substring(0, 50)}...`); try { // Build the endpoint URL for the appropriate provider const endpoint = `/providers/${this.provider}/messages`; // Prepare the request payload according to provider expectations let payload; if (this.provider === 'anthropic') { payload = { model: this.model, messages: [{ role: 'user', content: prompt }], max_tokens: 4000, temperature: 0.2 }; } else if (this.provider === 'openai') { payload = { model: this.model, messages: [{ role: 'user', content: prompt }], max_tokens: 4000, temperature: 0.2 }; } else { throw new Error(`Unsupported provider: ${this.provider}`); } const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': this.apiKey }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`Craftacoder API error: ${response.status} ${response.statusText}`); } const data = await response.json(); // Extract content based on provider response format let content = ''; if (this.provider === 'anthropic') { content = data.content[0].text; } else if (this.provider === 'openai') { content = data.choices[0].message.content; } return content; } catch (error) { console.error('Error calling Craftacoder API:', error); throw new Error(`Failed to get completion from Craftacoder: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Suggest an action based on the instruction and screen state */ async suggestAction(instruction, screenState) { console.log(`Suggesting action for: ${instruction}`); const prompt = ` You are an AI assistant helping to automate UI testing. Given the following instruction from a test scenario: "${instruction}" And the current screen state: ${JSON.stringify(screenState, null, 2)} Determine the most appropriate action to take. Return a JSON object with: - actionType: "click", "input", "navigate", "wait", "assert", etc. - target: Element to interact with (if applicable) - value: Value to input (if applicable) - reasoning: Why this action was chosen - confidence: A number between 0 and 1 indicating your confidence Response (JSON only): `; try { const content = await this.complete(prompt); // Extract JSON from the response const jsonMatch = content.match(/```json\n([\s\S]*?)\n```/) || content.match(/{[\s\S]*}/); if (jsonMatch) { const actionJson = JSON.parse(jsonMatch[1] || jsonMatch[0]); return { actionType: actionJson.actionType, target: actionJson.target, value: actionJson.value, reasoning: actionJson.reasoning, confidence: actionJson.confidence }; } throw new Error('Could not parse action from LLM response'); } catch (error) { console.error('Error getting action suggestion:', error); // Fallback action return { actionType: 'click', target: { text: 'Submit' }, reasoning: 'Fallback action due to API error', confidence: 0.5 }; } } /** * Verify if a condition is met based on the screen state */ async verifyCondition(condition, screenState) { console.log(`Verifying condition: ${condition}`); const prompt = ` You are an AI assistant helping to automate UI testing. Given the following condition to verify: "${condition}" And the current screen state: ${JSON.stringify(screenState, null, 2)} Determine if the condition is met. Return a JSON object with: - success: true or false - reason: Explanation of why the condition is met or not met Response (JSON only): `; try { const content = await this.complete(prompt); // Extract JSON from the response const jsonMatch = content.match(/```json\n([\s\S]*?)\n```/) || content.match(/{[\s\S]*}/); if (jsonMatch) { const resultJson = JSON.parse(jsonMatch[1] || jsonMatch[0]); return { success: resultJson.success, reason: resultJson.reason }; } throw new Error('Could not parse verification result from LLM response'); } catch (error) { console.error('Error verifying condition:', error); // Fallback verification return { success: true, reason: 'Fallback verification due to API error' }; } } } exports.CraftacoderAdapter = CraftacoderAdapter;