UNPKG

@salesforce/agents

Version:

Client side APIs for working with Salesforce agents

214 lines 8.23 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.AgentPreview = void 0; const node_crypto_1 = require("node:crypto"); const core_1 = require("@salesforce/core"); const agent_1 = require("./agent"); const maybe_mock_1 = require("./maybe-mock"); const apexUtils_1 = require("./apexUtils"); ; const messages = new core_1.Messages('@salesforce/agents', 'agentPreview', new Map([["invalidBotId", "The Bot ID provided must begin with \"0Xx\" and be either 15 or 18 characters. Found: %s"], ["agentApexDebuggingError", "Agent must have a user assigned to enable apex debug mode."]])); /** * A service to interact with an agent. Start an interactive session, * send messages to the agent, and end the session. * * **Examples** * * Create an instance of the service: * * `const agentPreview = new AgentPreview(connection, botId);` * * Start an interactive session: * * `const { sessionId } = await agentPreview.start();` * * Send a message to the agent using the session ID from the startResponse: * * `const sendResponse = await agentPreview.send(sessionId, message);` * * End an interactive session: * * `await agentPreview.end(sessionId, 'UserRequest');` * * Enable Apex Debug Mode: * * `agentPreview.toggleApexDebugMode(true);` */ class AgentPreview { apiBase = 'https://api.salesforce.com/einstein/ai-agent/v1'; connection; logger; maybeMock; apexDebugMode; apexTraceFlag; botId; /** * Create an instance of the service. * * @param connection The connection to use to make requests. * @param botId The ID of the agent (`Bot` ID). */ constructor(connection, botId) { this.connection = connection; this.logger = core_1.Logger.childFromRoot(this.constructor.name); this.maybeMock = new maybe_mock_1.MaybeMock(connection); if (!botId.startsWith('0Xx') || ![15, 18].includes(botId.length)) { throw messages.createError('invalidBotId', [botId]); } this.botId = botId; } /** * Start an interactive session with the agent. * * @returns `AgentPreviewStartResponse`, which includes a session ID needed for other actions. */ async start() { const url = `${this.apiBase}/agents/${this.botId}/sessions`; this.logger.debug(`Starting agent preview session for botId: ${this.botId}`); const body = { externalSessionKey: (0, node_crypto_1.randomUUID)(), instanceConfig: { endpoint: this.connection.instanceUrl, }, streamingCapabilities: { chunkTypes: ['Text'], }, bypassUser: true, }; try { return await this.maybeMock.request('POST', url, body); } catch (err) { throw core_1.SfError.wrap(err); } } /** * Send a message to the agent using the session ID obtained by calling `start()`. * * @param sessionId A session ID provided by first calling `agentPreview.start()`. * @param message A message to send to the agent. * @returns `AgentPreviewSendResponse` */ async send(sessionId, message) { const url = `${this.apiBase}/sessions/${sessionId}/messages`; const body = { message: { // https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-examples.html#send-synchronous-messages // > A number that you provide to represent the sequence ID. Increase this number for each subsequent message in this session. sequenceId: Date.now(), type: 'Text', text: message, }, variables: [], }; this.logger.debug(`Sending message to botId: ${this.botId} with apexDebugMode ${this.apexDebugMode ? 'enabled' : 'disabled'}`); try { // If apex debug mode is enabled, ensure we have a trace flag for the bot user and // if there isn't one, create one. const start = Date.now(); if (this.apexDebugMode) { await this.ensureTraceFlag(); } const response = await this.maybeMock.request('POST', url, body); if (this.apexDebugMode) { // get apex debug logs and look for a log within the start and end time const apexLog = await (0, apexUtils_1.getDebugLog)(this.connection, start, Date.now()); if (apexLog) { if (apexLog.Id) this.logger.debug(`Apex debug log ID for message is ${apexLog.Id}`); response.apexDebugLog = apexLog; } else { this.logger.debug('No apex debug log found for this message'); } } return response; } catch (err) { throw core_1.SfError.wrap(err); } } /** * Ends an interactive session with the agent. * * @param sessionId A session ID provided by first calling `agentPreview.start()`. * @param reason A reason why the interactive session was ended. * @returns `AgentPreviewEndResponse` */ async end(sessionId, reason) { const url = `${this.apiBase}/sessions/${sessionId}`; this.logger.debug(`Ending agent preview session for botId: ${this.botId} with sessionId: ${sessionId}`); try { // https://developer.salesforce.com/docs/einstein/genai/guide/agent-api-examples.html#end-session return await this.maybeMock.request('DELETE', url, undefined, { 'x-session-end-reason': reason, }); } catch (err) { throw core_1.SfError.wrap(err); } } /** * Get the status of the Agent API (UP | DOWN). * * @returns `ApiStatus` */ async status() { const base = 'https://test.api.salesforce.com'; const url = `${base}/einstein/ai-agent/v1/status`; try { return await this.maybeMock.request('GET', url); } catch (err) { throw core_1.SfError.wrap(err); } } /** * Enable or disable Apex Debug Mode, which will enable trace flags for the Bot user * and create apex debug logs for use within VS Code's Apex Replay Debugger. * * @param enable Whether to enable or disable Apex Debug Mode. */ toggleApexDebugMode(enable) { this.apexDebugMode = enable; this.logger.debug(`Apex Debug Mode is now ${enable ? 'enabled' : 'disabled'}`); } async getBotUserId() { const agent = new agent_1.Agent({ connection: this.connection, nameOrId: this.botId }); const botMetadata = await agent.getBotMetadata(); return botMetadata.BotUserId; } // If apex debug mode is enabled, ensure we have a trace flag for the bot user // that is not expired checking in this order: // 1. instance var (this.apexTraceFlag) // 2. query the org // 3. create a new trace flag async ensureTraceFlag() { if (this.apexTraceFlag) { const expDate = this.apexTraceFlag.ExpirationDate; if (expDate && new Date(expDate) > new Date()) { this.logger.debug(`Using cached apexTraceFlag with ExpirationDate of ${expDate}`); return; } else { this.logger.debug('Cached apex trace flag is expired'); } } const userId = await this.getBotUserId(); if (!userId) { throw messages.createError('agentApexDebuggingError'); } this.apexTraceFlag = await (0, apexUtils_1.findTraceFlag)(this.connection, userId); if (!this.apexTraceFlag) { await (0, apexUtils_1.createTraceFlag)(this.connection, userId); } } } exports.AgentPreview = AgentPreview; //# sourceMappingURL=agentPreview.js.map