UNPKG

@salesforce/agents

Version:

Client side APIs for working with Salesforce agents

348 lines (347 loc) 14.8 kB
import { Connection, SfProject } from '@salesforce/core'; import { type PlannerResponse, PreviewMetadata } from './types'; export declare const metric: readonly ["completeness", "coherence", "conciseness", "output_latency_milliseconds"]; /** * Sanitize a filename by removing or replacing illegal characters. * This ensures the filename is valid across different operating systems. * * @param filename - The filename to sanitize * @returns A sanitized filename safe for use across operating systems */ export declare const sanitizeFilename: (filename: string) => string; /** * Clean a string by replacing HTML entities with their respective characters. * * @param str - The string to clean. * @returns The cleaned string with all HTML entities replaced with their respective characters. */ export declare const decodeHtmlEntities: (str?: string) => string; /** * Find the authoring bundle directory for a given bot name by recursively searching from a starting directory or directories. * * @param dirOrDirs - The directory or array of directories to start searching from * @param botName - The name of the bot to find the authoring bundle directory for * @returns The path to the authoring bundle directory if found, undefined otherwise */ export declare const findAuthoringBundle: (dirOrDirs: string | string[], botName: string) => string | undefined; /** * Find all local agent files matching the pattern aiAuthoringBundles/<name>/<name>.agent * Only descends into aiAuthoringBundles to check direct children (no full tree walk under it). * * @param dir - The directory to start searching from * @returns Array of paths to agent files */ export declare const findLocalAgents: (dir: string) => string[]; /** * takes a connection and upgrades it to a NamedJWT connection * * @param {Connection} connection original Connection * @returns {Promise<Connection>} upgraded connection */ export declare const useNamedUserJwt: (connection: Connection) => Promise<Connection>; export type TranscriptRole = 'user' | 'agent'; export type TranscriptEntry = { timestamp: string; agentId: string; sessionId: string; role: TranscriptRole; text?: string; reason?: string; raw?: any; }; export type TurnIndexEntry = { turn: number; timestamp: string; role: TranscriptRole; summary: string; summaryTruncated: boolean; multiModal: string | null; traceFile: string | null; planId: string | null; reason?: string; }; export type TurnIndex = { version: string; sessionId: string; agentId: string; created: string; turns: TurnIndexEntry[]; }; /** * returns a path, and ensures it's created, to the agents history directory * * Initialize session directory * Session directory structure: * .sfdx/agents/<agentId>/sessions/<sessionId>/ * ├── transcript.jsonl # All transcript entries (one per line) * ├── turn-index.json # Turn-trace correlation index * ├── traces/ # Individual trace files * │ ├── <planId1>.json * │ └── <planId2>.json * └── metadata.json # Session metadata (start time, end time, planIds, etc.) * * @param {string} agentId gotten from Agent.getAgentIdForStorage() * @param {string} sessionId the preview's start call .SessionId * @returns {Promise<string>} path to where history/metadata/transcripts are stored inside of local .sfdx */ export declare const getHistoryDir: (agentId: string, sessionId: string) => Promise<string>; /** * Get the path to the agent index directory. Create the directory if it doesn't exist. * * .sfdx/agents/<agentId>/ <-- returns this directory path * ├── index.md # Session index file * │── sessions/ # Session directories * │ ├── <sessionId1>/ # Session 1 directory * │ └── <sessionId2>/ # Session 2 directory * * @param {string} agentId * @returns {Promise<string>} path to the agent index directory */ export declare const getAgentIndexDir: (agentId: string) => Promise<string>; /** * Append a transcript entry to the transcript.jsonl transcript file * * @param {TranscriptEntry} entry to save * @param {string} sessionDir the preview's start call .SessionId * @returns {Promise<void>} */ export declare const appendTranscriptToHistory: (entry: TranscriptEntry, sessionDir: string) => Promise<void>; /** * writes a trace to <plan-id>.json in history directory * * @param {string} planId * @param {PlannerResponse | undefined} trace * @param {string} historyDir * @returns {Promise<void>} */ export declare const writeTraceToHistory: (planId: string, trace: PlannerResponse | undefined, historyDir: string) => Promise<void>; export type TraceFileInfo = { planId: string; path: string; size: number; mtime: Date; }; /** * List trace files for a given agent session. * * Returns one entry per .json file in the session's traces/ directory. * File path is absolute. Returns an empty array if the traces directory does not exist. */ export declare const listSessionTraces: (agentId: string, sessionId: string) => Promise<TraceFileInfo[]>; /** * Read a single trace file by planId. Returns null if the file does not exist or cannot be parsed. */ export declare const readSessionTrace: (agentId: string, sessionId: string, planId: string) => Promise<PlannerResponse | null>; /** * Read the turn-index.json for a session. Returns null if not found. */ export declare const readTurnIndex: (agentId: string, sessionId: string) => Promise<TurnIndex | null>; /** * Write or append a session line to .sfdx/agents/<agentId>/index.md. * If the file does not exist, creates it with a header and the session line. * If it exists, appends the new session line. */ export declare const logSessionToIndex: (agentDir: string, options: { sessionId: string; startTime: string; simulated: boolean; agentId: string; }) => Promise<void>; /** * In-memory buffer for session history to minimize file I/O during conversation */ export declare class SessionHistoryBuffer { private readonly sessionDir; private readonly sessionId; private readonly agentId; private readonly created; private readonly mockMode?; private turnEntries; private planIds; constructor(sessionDir: string, sessionId: string, agentId: string, created: string, mockMode?: "Mock" | "Live Test" | undefined); /** * Create a SessionHistoryBuffer from existing session data on disk * Used when resuming an existing session */ static fromDisk(sessionDir: string, sessionId: string, agentId: string): Promise<{ buffer: SessionHistoryBuffer; turnCount: number; }>; /** * Add a turn to the buffer (no file I/O) */ addTurn(entry: TurnIndexEntry): void; /** * Add a planId to the buffer (no file I/O) */ addPlanId(planId: string): void; /** * Update an existing turn with trace info (no file I/O) */ updateTurnWithTrace(turnNumber: number, planId: string): void; /** * Flush all buffered data to disk * Called at session start (to create initial files), after each turn (to keep real-time), and at session end (to finalize) */ flush(endTime?: string): Promise<void>; } /** * Log a turn to history using buffer (fast, no read-modify-write) * * @param {TranscriptEntry} entry the transcript entry to log * @param {number} turnNumber the turn number (1-based) * @param {string} sessionDir path to the session directory * @param {SessionHistoryBuffer} buffer buffer for batched writes * @returns {Promise<void>} */ export declare const logTurnToHistory: (entry: TranscriptEntry, turnNumber: number, sessionDir: string, buffer: SessionHistoryBuffer) => Promise<void>; /** * Extract HTTP status code from API errors. Supports: * - ERROR_HTTP_404 / ERROR_HTTP_500 style (name, errorCode, or data.errorCode) * - Numeric statusCode on error, cause, or response */ export declare function getHttpStatusCode(err: unknown): number | undefined; export type RequestInfo = { url: string; method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD'; headers?: Record<string, string>; body?: string; }; /** * Makes an API request with automatic endpoint fallback. * Tries api.salesforce.com first, then test.api.salesforce.com on 404, then dev.api.salesforce.com on 404. * * @param connection - The Salesforce connection * @param requestInfo - The request information (url, method, headers, body, etc.) * @param options - Optional retry/timeout options * @returns The API response * @throws SfError if all endpoints return 404, or immediately on non-404 errors */ export declare function requestWithEndpointFallback<T>(connection: Connection, requestInfo: RequestInfo, options?: { retry?: { maxRetries?: number; }; }): Promise<T>; /** * Record a trace for a turn using buffer (fast, minimal I/O) * * @param {string} historyDir path to the session directory * @param {number} turnNumber the turn number that generated this trace * @param {string} planId the plan ID for this trace * @param {PlannerResponse | undefined} trace the trace data to write * @param {SessionHistoryBuffer} buffer buffer for batched updates * @returns {Promise<void>} */ export declare const recordTraceForTurn: (historyDir: string, turnNumber: number, planId: string, trace: PlannerResponse | undefined, buffer: SessionHistoryBuffer) => Promise<void>; /** * Get all history data for a session including metadata, transcript, and traces * * @param agentId gotten from Agent.getAgentIdForStorage() * @param sessionId optional - the preview sessions' ID, gotten originally from /start .SessionId. If not provided, returns the most recent conversation * @returns Object containing parsed metadata, transcript entries, and traces */ export declare const getAllHistory: (agentId: string, sessionId: string | undefined) => Promise<{ metadata: PreviewMetadata | null; transcript: TranscriptEntry[]; traces: PlannerResponse[]; }>; /** * Read and parse the last conversation's transcript entries from JSON. * * @param agentId gotten from Agent.getAgentIdForStorage() * @param sessionId the preview sessions' ID, gotten originally from /start .SessionId * @returns Array of TranscriptEntry in file order (chronological append order). */ export declare const readTranscriptEntries: (agentId: string, sessionId: string) => Promise<TranscriptEntry[]>; export type TestRunnerType = 'agentforce-studio' | 'testing-center'; /** Detects the test runner from a run ID's Salesforce ID prefix (`3A2` = Agentforce Studio, `4KB` = Testing Center). */ export declare function detectTestRunnerFromId(runId: string): TestRunnerType | undefined; /** * Determines which test runner to use based on available metadata types in the org. * * This function checks for the presence of: * - `AiEvaluationDefinition` (Testing Center) * - `AiTestingDefinition` (Agentforce Studio) * * If a test definition with the same name exists in both metadata types, an error is thrown * to prevent ambiguity. * * @param connection - The Salesforce connection * @param testDefinitionName - Optional test definition name to check for conflicts * @returns 'agentforce-studio' if only Agentforce Studio metadata exists, 'testing-center' if only Testing Center metadata exists * @throws {SfError} if both metadata types exist with the same test definition name * @throws {SfError} if neither metadata type exists * * @example * ```typescript * const runnerType = await determineTestRunner(connection, 'MyTestSuite'); * if (runnerType === 'agentforce-studio') { * const tester = new AgentforceStudioTester(connection); * } else { * const tester = new AgentTester(connection); * } * ``` */ export declare function determineTestRunner(connection: Connection, testDefinitionName?: string): Promise<TestRunnerType>; export type SessionType = 'simulated' | 'live' | 'published'; export type PreviewSessionMeta = { displayName?: string; timestamp?: string; sessionType?: SessionType; }; /** * Save a marker so send/end can validate that the session was started for this agent. * Caller must have started the session (agent has sessionId set). Uses agent.getHistoryDir() for the path. * Pass displayName (authoring bundle name or production agent API name) so "agent preview sessions" can show it. */ export declare function createPreviewSessionCache(agent: { getHistoryDir: () => Promise<string>; }, options?: { displayName?: string; sessionType?: SessionType; }): Promise<void>; /** * Validate that the session was started for this agent (marker file exists in agent's history dir for current sessionId). * Caller must set sessionId on the agent (agent.setSessionId) before calling. * Throws SfError if the session marker is not found. */ export declare function validatePreviewSession(agent: { getHistoryDir: () => Promise<string>; }): Promise<void>; /** * Remove the session marker so this session is no longer considered "active" for send/end without --session-id. * Call after ending the session. Caller must set sessionId on the agent before calling. */ export declare function removePreviewSessionCache(agent: { getHistoryDir: () => Promise<string>; }): Promise<void>; /** * List session IDs that have a cache marker (started via "agent preview start") for this agent. * Uses project path and agent's storage ID to find .sfdx/agents/<agentId>/sessions/<sessionId>/session-meta.json. */ export declare function getCachedPreviewSessionIds(project: SfProject, agent: { getAgentIdForStorage: () => string | Promise<string>; }): Promise<string[]>; /** * Return the single "current" session ID when safe: exactly one cached session for this agent. * Returns undefined when there are zero or multiple sessions (caller should require --session-id). */ export declare function getCurrentPreviewSessionId(project: SfProject, agent: { getAgentIdForStorage: () => string | Promise<string>; }): Promise<string | undefined>; export type CachedPreviewSessionInfo = { sessionId: string; timestamp?: string; sessionType?: SessionType; }; export type CachedPreviewSessionEntry = { agentId: string; displayName?: string; sessions: CachedPreviewSessionInfo[]; }; /** * List all cached preview sessions in the project, grouped by agent ID. * displayName (when present in session-meta.json) is the authoring bundle name or production agent API name for display. * Use this to show users which sessions exist so they can end or clean up. */ export declare function listCachedPreviewSessions(project: SfProject): Promise<CachedPreviewSessionEntry[]>;