UNPKG

@salesforce/agents

Version:

Client side APIs for working with Salesforce agents

258 lines 10.2 kB
"use strict"; /* * Copyright 2025, Salesforce, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentPreview = void 0; const node_crypto_1 = require("node:crypto"); const core_1 = require("@salesforce/core"); const kit_1 = require("@salesforce/kit"); const agent_1 = require("./agent"); const agentPreviewBase_1 = require("./agentPreviewBase"); const utils_1 = require("./utils"); 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 extends agentPreviewBase_1.AgentPreviewBase { apiBase = `https://${kit_1.env.getBoolean('SF_TEST_API') ? 'test.' : ''}api.salesforce.com/einstein/ai-agent/v1`; 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) { super({ 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 { const response = await this.maybeMock.request('POST', url, body); // Persist any initial agent messages (welcome, etc.) await (0, utils_1.appendTranscriptEntry)({ timestamp: new Date().toISOString(), agentId: this.botId, sessionId: response.sessionId, role: 'agent', text: response.messages.map((m) => m.message).join('\n'), raw: response.messages, }, true); return response; } 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); // Save user entry await (0, utils_1.appendTranscriptEntry)({ timestamp: new Date().toISOString(), agentId: this.botId, sessionId, role: 'user', text: message, }); // Save agent response entry const agentText = (response.messages ?? []) .map((m) => m.message) .filter(Boolean) .join('\n'); await (0, utils_1.appendTranscriptEntry)({ timestamp: new Date().toISOString(), agentId: this.botId, sessionId, role: 'agent', text: agentText || undefined, raw: response.messages, }); 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 const response = await this.maybeMock.request('DELETE', url, undefined, { 'x-session-end-reason': reason, }); await (0, utils_1.appendTranscriptEntry)({ timestamp: new Date().toISOString(), agentId: this.botId, sessionId, role: 'agent', reason, raw: response.messages, }); return response; } catch (err) { throw core_1.SfError.wrap(err); } } /** * Get the status of the Agent API (UP | DOWN). * * @returns `ApiStatus` */ async status() { const url = `https://${kit_1.env.getBoolean('SF_TEST_API') ? 'test.' : ''}api.salesforce.com/einstein/ai-agent/v1/status`; try { return await this.maybeMock.request('GET', url); } catch (err) { throw core_1.SfError.wrap(err); } } /** * Get the traces for a given session and message IDs. * * @param sessionId A session ID provided by first calling `start()`. * @param messageIds An array of message IDs to get the traces for. * @returns `AgentPreviewEndResponse` */ traces(sessionId, messageIds) { this.logger.info(`Get traces for published agents is not implemented yet. Session ID: ${sessionId}, Message IDs: ${messageIds.join(', ')}`); return Promise.resolve([]); } 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