UNPKG

@salesforce/agents

Version:

Client side APIs for working with Salesforce agents

174 lines 6.4 kB
"use strict"; /* * Copyright (c) 2024, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentTester = void 0; exports.normalizeResults = normalizeResults; const core_1 = require("@salesforce/core"); const kit_1 = require("@salesforce/kit"); const maybe_mock_1 = require("./maybe-mock"); const utils_1 = require("./utils"); /** * A service for testing agents using `AiEvaluationDefinition` metadata. Start asynchronous * test runs, get or poll for test status, and get detailed test results. * * **Examples** * * Create an instance of the service: * * `const agentTester = new AgentTester(connection);` * * Start a test run: * * `const startResponse = await agentTester.start(aiEvalDef);` * * Get the status for a test run: * * `const status = await agentTester.status(startResponse.runId);` * * Get detailed results for a test run: * * `const results = await agentTester.results(startResponse.runId);` */ class AgentTester { maybeMock; constructor(connection) { this.maybeMock = new maybe_mock_1.MaybeMock(connection); } /** * Initiates a test run (i.e., AI evaluation). * * @param aiEvalDefName - The name of the AI evaluation definition to run. * @returns Promise that resolves with the response from starting the test. */ async start(aiEvalDefName) { const url = '/einstein/ai-evaluations/runs'; return this.maybeMock.request('POST', url, { aiEvaluationDefinitionName: aiEvalDefName, }); } /** * Get the status of a test run. * * @param {string} jobId * @returns {Promise<AgentTestStatusResponse>} */ async status(jobId) { const url = `/einstein/ai-evaluations/runs/${jobId}`; return this.maybeMock.request('GET', url); } /** * Poll the status of a test run until the tests are complete or the timeout is reached. * * @param {string} jobId * @param {Duration} timeout * @returns {Promise<AgentTestResultsResponse>} */ async poll(jobId, { timeout = kit_1.Duration.minutes(5), } = { timeout: kit_1.Duration.minutes(5), }) { const frequency = kit_1.env.getNumber('SF_AGENT_TEST_POLLING_FREQUENCY_MS', 1000); const lifecycle = core_1.Lifecycle.getInstance(); const client = await core_1.PollingClient.create({ poll: async () => { const statusResponse = await this.status(jobId); if (statusResponse.status.toLowerCase() !== 'new') { const resultsResponse = await this.results(jobId); const totalTestCases = resultsResponse.testCases.length; const passingTestCases = resultsResponse.testCases.filter((tc) => tc.status.toLowerCase() === 'completed' && tc.testResults.every((r) => r.result === 'PASS')).length; const failingTestCases = resultsResponse.testCases.filter((tc) => ['error', 'completed'].includes(tc.status.toLowerCase()) && tc.testResults.some((r) => r.result === 'FAILURE')).length; if (resultsResponse.status.toLowerCase() === 'completed') { await lifecycle.emit('AGENT_TEST_POLLING_EVENT', { jobId, status: resultsResponse.status, totalTestCases, failingTestCases, passingTestCases, }); return { payload: resultsResponse, completed: true }; } await lifecycle.emit('AGENT_TEST_POLLING_EVENT', { jobId, status: resultsResponse.status, totalTestCases, failingTestCases, passingTestCases, }); } return { completed: false }; }, frequency: kit_1.Duration.milliseconds(frequency), timeout, }); return client.subscribe(); } /** * Get detailed test run results. * * @param {string} jobId * @returns {Promise<AgentTestResultsResponse>} */ async results(jobId) { const url = `/einstein/ai-evaluations/runs/${jobId}/results`; const results = await this.maybeMock.request('GET', url); return normalizeResults(results); } /** * Cancel an in-progress test run. * * @param {string} jobId * @returns {Promise<{success: boolean}>} */ async cancel(jobId) { const url = `/einstein/ai-evaluations/runs/${jobId}/cancel`; return this.maybeMock.request('POST', url); } } exports.AgentTester = AgentTester; /** * Normalizes test results by decoding HTML entities in utterances and test result values. * * @param results - The agent test results response object to normalize * @returns A new AgentTestResultsResponse with decoded HTML entities * * @example * ``` * const results = { * testCases: [{ * inputs: { utterance: "&quot;hello&quot;" }, * testResults: [{ * actualValue: "&amp;test", * expectedValue: "&lt;value&gt;" * }] * }] * }; * const normalized = normalizeResults(results); * ``` */ function normalizeResults(results) { return { ...results, testCases: results.testCases.map((tc) => ({ ...tc, generatedData: { ...tc.generatedData, invokedActions: (0, utils_1.decodeHtmlEntities)(tc.generatedData.invokedActions), }, inputs: { utterance: (0, utils_1.decodeHtmlEntities)(tc.inputs.utterance), }, testResults: tc.testResults.map((r) => ({ ...r, actualValue: (0, utils_1.decodeHtmlEntities)(r.actualValue), expectedValue: (0, utils_1.decodeHtmlEntities)(r.expectedValue), metricExplainability: (0, utils_1.decodeHtmlEntities)(r.metricExplainability), })), })), }; } //# sourceMappingURL=agentTester.js.map