UNPKG

@hashgraphonline/standards-agent-kit

Version:

A modular SDK for building on-chain autonomous agents using Hashgraph Online Standards, including HCS-10 for agent discovery and communication.

250 lines (249 loc) 8.68 kB
import { updateEnvFile } from "./standards-agent-kit.es42.js"; import { Logger, ConnectionsManager } from "@hashgraphonline/standards-sdk"; class OpenConvaiState { /** * Creates a new OpenConvaiState instance * @param options - Options for environment variable persistence */ constructor(options) { this.currentAgent = null; this.connectionMessageTimestamps = {}; this.connectionsManager = null; this.defaultEnvFilePath = options?.defaultEnvFilePath; this.defaultPrefix = options?.defaultPrefix ?? "TODD"; const shouldSilence = options?.disableLogging || process.env.DISABLE_LOGGING === "true"; this.logger = new Logger({ module: "OpenConvaiState", silent: shouldSilence }); if (options?.baseClient) { this.initializeConnectionsManager(options.baseClient); } } /** * Initializes the ConnectionsManager * @param baseClient - HCS10BaseClient instance to use */ initializeConnectionsManager(baseClient) { if (!this.connectionsManager) { this.logger.debug("Initializing ConnectionsManager"); this.connectionsManager = new ConnectionsManager({ baseClient, logLevel: "error" }); } else { this.logger.debug("ConnectionsManager already initialized"); } return this.connectionsManager; } /** * Gets the ConnectionsManager instance * @returns The ConnectionsManager instance, or null if not initialized */ getConnectionsManager() { return this.connectionsManager; } /** * Sets the current active agent and clears any previous connection data. * This should be called when switching between agents. */ setCurrentAgent(agent) { this.currentAgent = agent; this.connectionMessageTimestamps = {}; if (this.connectionsManager) { this.connectionsManager.clearAll(); } } /** * Returns the currently active agent or null if none is set. */ getCurrentAgent() { return this.currentAgent; } /** * Adds a new connection to the active connections list. * Ensures no duplicates are added based on connectionTopicId. * Initializes timestamp tracking for the connection. */ addActiveConnection(connection) { if (!this.connectionsManager) { this.logger.error( "ConnectionsManager not initialized. Call initializeConnectionsManager before adding connections." ); throw new Error( "ConnectionsManager not initialized. Call initializeConnectionsManager before adding connections." ); } const sdkConnection = { connectionTopicId: connection.connectionTopicId, targetAccountId: connection.targetAccountId, targetAgentName: connection.targetAgentName, targetInboundTopicId: connection.targetInboundTopicId, status: this.convertConnectionStatus(connection.status || "established"), isPending: connection.isPending || false, needsConfirmation: connection.needsConfirmation || false, created: connection.created || /* @__PURE__ */ new Date(), lastActivity: connection.lastActivity, profileInfo: connection.profileInfo, connectionRequestId: connection.connectionRequestId, processed: true }; this.connectionsManager.updateOrAddConnection(sdkConnection); this.initializeTimestampIfNeeded(connection.connectionTopicId); } /** * Updates an existing connection or adds it if not found. * Preserves existing properties when updating by merging objects. */ updateOrAddConnection(connection) { this.addActiveConnection(connection); } /** * Returns a copy of all active connections. */ listConnections() { if (!this.connectionsManager) { this.logger.debug( "ConnectionsManager not initialized, returning empty connections list" ); return []; } return this.connectionsManager.getAllConnections().map((conn) => this.convertToActiveConnection(conn)); } /** * Finds a connection by its identifier, which can be: * - A 1-based index as displayed in the connection list * - A target account ID string * - A connection topic ID string */ getConnectionByIdentifier(identifier) { if (!this.connectionsManager) { return void 0; } const connections = this.listConnections(); const numericIndex = parseInt(identifier) - 1; if (!isNaN(numericIndex) && numericIndex >= 0 && numericIndex < connections.length) { return connections[numericIndex]; } const byTopicId = this.connectionsManager.getConnectionByTopicId(identifier); if (byTopicId) { return this.convertToActiveConnection(byTopicId); } const byAccountId = this.connectionsManager.getConnectionByAccountId(identifier); if (byAccountId) { return this.convertToActiveConnection(byAccountId); } return void 0; } /** * Gets the last processed message timestamp for a connection. * Returns 0 if no timestamp has been recorded. */ getLastTimestamp(connectionTopicId) { return this.connectionMessageTimestamps[connectionTopicId] || 0; } /** * Updates the last processed message timestamp for a connection, * but only if the new timestamp is more recent than the existing one. */ updateTimestamp(connectionTopicId, timestampNanos) { if (!(connectionTopicId in this.connectionMessageTimestamps)) { this.connectionMessageTimestamps[connectionTopicId] = timestampNanos; return; } const currentTimestamp = this.connectionMessageTimestamps[connectionTopicId]; if (timestampNanos > currentTimestamp) { this.connectionMessageTimestamps[connectionTopicId] = timestampNanos; } } /** * Helper method to initialize timestamp tracking for a connection * if it doesn't already exist. */ initializeTimestampIfNeeded(connectionTopicId) { if (!(connectionTopicId in this.connectionMessageTimestamps)) { this.connectionMessageTimestamps[connectionTopicId] = Date.now() * 1e6; } } /** * Converts ConnectionStatus to SDK status format */ convertConnectionStatus(status) { switch (status) { case "pending": return "pending"; case "established": return "established"; case "needs confirmation": return "needs_confirmation"; default: return "established"; } } /** * Converts SDK Connection to ActiveConnection */ convertToActiveConnection(conn) { return { targetAccountId: conn.targetAccountId, targetAgentName: conn.targetAgentName || `Agent ${conn.targetAccountId}`, targetInboundTopicId: conn.targetInboundTopicId || "", connectionTopicId: conn.connectionTopicId, status: this.convertToStateStatus(conn.status), created: conn.created, lastActivity: conn.lastActivity, isPending: conn.isPending, needsConfirmation: conn.needsConfirmation, profileInfo: conn.profileInfo, connectionRequestId: conn.connectionRequestId }; } /** * Converts SDK status to state status format */ convertToStateStatus(status) { switch (status) { case "pending": return "pending"; case "established": return "established"; case "needs_confirmation": return "needs confirmation"; case "closed": return "established"; // Mapping closed to established for compatibility default: return "unknown"; } } /** * Persists agent data to environment variables * @param agent - The agent data to persist * @param options - Environment file persistence options */ async persistAgentData(agent, options) { if (options?.type && options.type !== "env-file") { throw new Error( `Unsupported persistence type: ${options.type}. Only 'env-file' is supported.` ); } const envFilePath = options?.envFilePath || this.defaultEnvFilePath || process.env.ENV_FILE_PATH || ".env"; const prefix = options?.prefix || this.defaultPrefix; if (!agent.accountId || !agent.inboundTopicId || !agent.outboundTopicId) { throw new Error("Agent data incomplete, cannot persist to environment"); } const updates = { [`${prefix}_ACCOUNT_ID`]: agent.accountId, [`${prefix}_INBOUND_TOPIC_ID`]: agent.inboundTopicId, [`${prefix}_OUTBOUND_TOPIC_ID`]: agent.outboundTopicId }; if (agent.privateKey) { updates[`${prefix}_PRIVATE_KEY`] = agent.privateKey; } if (agent.profileTopicId) { updates[`${prefix}_PROFILE_TOPIC_ID`] = agent.profileTopicId; } await updateEnvFile(envFilePath, updates); } } export { OpenConvaiState }; //# sourceMappingURL=standards-agent-kit.es38.js.map