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.

138 lines (120 loc) 5.17 kB
import { StructuredTool, ToolParams } from '@langchain/core/tools'; import { z } from 'zod'; import { HCS10Client } from '../hcs10/HCS10Client'; import { IStateManager, ActiveConnection } from '../state/state-types'; import { Logger } from '@hashgraphonline/standards-sdk'; export interface InitiateConnectionToolParams extends ToolParams { hcsClient: HCS10Client; stateManager: IStateManager; } /** * A tool to actively START a NEW HCS-10 connection TO a target agent. * Requires the target agent's account ID. * It retrieves their profile, sends a connection request, waits for confirmation, and stores the connection using the provided stateManager. * Use this tool ONLY to actively INITIATE an OUTGOING connection. */ export class InitiateConnectionTool extends StructuredTool { name = 'initiate_connection'; description = 'Actively STARTS a NEW HCS-10 connection TO a specific target agent identified by their account ID. Requires the targetAccountId parameter. Use this ONLY to INITIATE an OUTGOING connection request.'; schema = z.object({ targetAccountId: z .string() .describe( 'The Hedera account ID (e.g., 0.0.12345) of the agent you want to connect with.' ) }); private hcsClient: HCS10Client; private stateManager: IStateManager; private logger: Logger; constructor({ hcsClient, stateManager, ...rest }: InitiateConnectionToolParams) { super(rest); this.hcsClient = hcsClient; this.stateManager = stateManager; this.logger = Logger.getInstance({ module: 'InitiateConnectionTool' }); } protected async _call({ targetAccountId }: z.infer<this['schema']>): Promise<string> { const currentAgent = this.stateManager.getCurrentAgent(); if (!currentAgent) { return 'Error: Cannot initiate connection. No agent is currently active. Please register or select an agent first.'; } this.logger.info( `Attempting connection from ${currentAgent.accountId} to ${targetAccountId}` ); try { this.logger.debug(`Retrieving profile for ${targetAccountId}...`); const targetProfile = await this.hcsClient.getAgentProfile( targetAccountId ); if (!targetProfile?.topicInfo?.inboundTopic) { return `Error: Could not retrieve profile or find inbound topic ID for target agent ${targetAccountId}. They might not be registered or have a public profile.`; } const targetInboundTopicId = targetProfile.topicInfo.inboundTopic; const targetAgentName = targetProfile.profile.name || `Agent ${targetAccountId}`; const requestResult = await this.hcsClient.submitConnectionRequest( targetInboundTopicId, currentAgent.name ); const sequenceNumberLong = requestResult?.topicSequenceNumber; if (!sequenceNumberLong) { throw new Error('Connection request sequence number not found.'); } let connectionRequestId: number; try { connectionRequestId = sequenceNumberLong.toNumber(); if (isNaN(connectionRequestId)) { throw new Error('Converted sequence number is NaN.'); } } catch (conversionError) { throw new Error( `Failed to convert connection request sequence number: ${conversionError}` ); } const confirmationTimeoutMs = 60000; const delayMs = 2000; const maxAttempts = Math.ceil(confirmationTimeoutMs / delayMs); const confirmationResult = await this.hcsClient.waitForConnectionConfirmation( targetInboundTopicId, connectionRequestId, maxAttempts, delayMs ); if (!confirmationResult?.connectionTopicId) { return `Error: Connection confirmation not received from ${targetAccountId} (for request ${connectionRequestId}) within ${ confirmationTimeoutMs / 1000 } seconds.`; } const connectionTopicId = confirmationResult.connectionTopicId; this.logger.info(`Connection confirmed! Topic ID: ${connectionTopicId}`); const newConnection: ActiveConnection = { targetAccountId: targetAccountId, targetAgentName: targetAgentName, targetInboundTopicId: targetInboundTopicId, connectionTopicId: connectionTopicId, }; this.stateManager.addActiveConnection(newConnection); const connections = this.stateManager.listConnections(); const addedEntry = connections.find( (c) => c.connectionTopicId === connectionTopicId ); const localConnectionId = addedEntry ? connections.indexOf(addedEntry) + 1 : null; const idString = localConnectionId ? `#${localConnectionId}` : ''; return `Successfully established connection ${idString} with ${targetAgentName} (${targetAccountId}). Connection Topic: ${connectionTopicId}. You can now send messages using this connection.`; } catch (error) { this.logger.error(`Connection initiation failed: ${error}`); return `Error initiating connection with ${targetAccountId}: ${ error instanceof Error ? error.message : String(error) }`; } } }