@salesforce/agents
Version:
Client side APIs for working with Salesforce agents
169 lines • 7.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgentBase = void 0;
/*
* Copyright 2026, 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.
*/
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
const core_1 = require("@salesforce/core");
const utils_1 = require("../utils");
const connectionManager_1 = require("../connectionManager");
/**
* Abstract base class for agent preview functionality.
* Contains shared properties and methods between ScriptAgent and ProductionAgent.
*/
class AgentBase {
/**
* The display name of the agent (user-friendly name, not API name)
*/
name;
/**
* The Connection passed in by the caller. Used as the lookup key into the ConnectionManager
* cache (see managerFor()) — never used directly for SFAP or org API calls. Subclasses go
* through getJwtConnection() / getStandardConnection() so that JWT and standard connections
* remain isolated.
*/
connection;
sessionId;
historyDir;
historyBuffer;
turnCounter = 0;
apexDebugging;
planIds = new Set();
constructor(connection) {
this.connection = connection;
}
/**
* Refreshes the access token on the standard connection.
*
* Retained for backward compatibility. The caller's original Connection is never mutated
* by agent operations, so this only refreshes the internal standard connection owned by
* the ConnectionManager.
*/
async restoreConnection() {
const manager = await (0, connectionManager_1.managerFor)(this.connection);
await manager.refreshStandardConnection();
}
setSessionId(sessionId) {
this.sessionId = sessionId;
}
async getHistoryDir() {
if (!this.sessionId) {
throw core_1.SfError.create({ message: 'No sessionId set on agent. Call setSessionId() before getHistoryDir().' });
}
return (0, utils_1.getHistoryDir)(await this.getAgentIdForStorage(), this.sessionId);
}
/**
* Resume an existing session by loading session state from disk
*
* @param sessionId The session ID to resume
*/
async resumeSession(sessionId) {
this.sessionId = sessionId;
const agentId = await this.getAgentIdForStorage();
this.historyDir = await (0, utils_1.getHistoryDir)(agentId, sessionId);
// Load session data from disk
const { buffer, turnCount } = await utils_1.SessionHistoryBuffer.fromDisk(this.historyDir, sessionId, agentId);
this.historyBuffer = buffer;
this.turnCounter = turnCount;
// Load planIds from buffer
const history = await this.getHistoryFromDisc();
if (history.metadata?.planIds) {
history.metadata.planIds.forEach((planId) => this.planIds.add(planId));
}
}
/**
* Returns the connection to use for SFAP API calls (api.salesforce.com/einstein/ai-agent).
* Always the JWT-upgraded connection from the ConnectionManager — never the caller's
* original Connection.
*/
async getJwtConnection() {
const manager = await (0, connectionManager_1.managerFor)(this.connection);
return manager.getJwtConnection();
}
/**
* Returns the standard org connection for SOQL queries, tooling API, and metadata
* operations. Always the manager's isolated standard connection — never the caller's
* original Connection — to keep JWT and org auth fully separate.
*/
async getStandardConnection() {
const manager = await (0, connectionManager_1.managerFor)(this.connection);
return manager.getStandardConnection();
}
/**
* Get all traces from the current session
* Reads traces from the session directory if available, otherwise fetches from API
*/
async getAllTracesFromDisc() {
if (!this.historyDir) {
throw core_1.SfError.create({ message: 'history never created' });
}
const traces = [];
// If we have a session directory, try reading traces from disk first
const tracesDir = (0, node_path_1.join)(this.historyDir, 'traces');
const files = await (0, promises_1.readdir)(tracesDir);
const tracePromises = files
.filter((file) => file.endsWith('.json'))
.map(async (file) => {
const traceData = await (0, promises_1.readFile)((0, node_path_1.join)(tracesDir, file), 'utf-8');
return JSON.parse(traceData);
});
traces.push(...(await Promise.all(tracePromises)));
return traces;
}
/**
* Save the complete session data to disk by copying the session directory.
* The session directory is already populated during the session with:
* - Transcript entries (transcript.jsonl)
* - Traces (traces/*.json)
* - Session metadata (metadata.json)
*
* Session directory structure:
* .sfdx/agents/<agentId>/sessions/<sessionId>/
* ├── transcript.jsonl # All transcript entries (one per line)
* ├── traces/ # Individual trace files
* │ ├── <planId1>.json
* │ └── <planId2>.json
* └── metadata.json # Session metadata (start time, end time, planIds, etc.)
*
* @param outputDir Optional output directory. If not provided, uses default location.
* @returns The path to the copied session directory
*/
async saveSessionTo(outputDir) {
if (!this.sessionId || !this.historyDir) {
throw core_1.SfError.create({ name: 'noSessionId', message: 'No active session. Call .start() first.' });
}
const agentId = await this.getAgentIdForStorage();
// Determine output directory
const destDir = (0, node_path_1.join)(outputDir, agentId, `session_${this.sessionId}`);
// Copy the entire session directory from .sfdx to the output directory
// This includes transcript.jsonl, traces/, and metadata.json
await (0, promises_1.mkdir)(destDir, { recursive: true });
await (0, promises_1.cp)(this.historyDir, destDir, { recursive: true });
return destDir;
}
/**
* Set the Apex debugging mode for the agent preview.
* This can be called before starting a session.
*
* @param apexDebugging true to enable Apex debugging, false to disable
*/
setApexDebugging(apexDebugging) {
this.apexDebugging = apexDebugging;
}
}
exports.AgentBase = AgentBase;
//# sourceMappingURL=agentBase.js.map