@hashgraphonline/standards-agent-kit 0.0.37 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/cjs/builders/hcs10/hcs10-builder.d.ts +262 -0
  2. package/dist/cjs/builders/index.d.ts +2 -0
  3. package/dist/cjs/builders/types.d.ts +10 -0
  4. package/dist/cjs/index.d.ts +3 -1
  5. package/dist/cjs/init/init.d.ts +21 -22
  6. package/dist/cjs/plugins/PluginInterface.d.ts +4 -80
  7. package/dist/cjs/plugins/PluginRegistry.d.ts +1 -47
  8. package/dist/cjs/plugins/defi/index.d.ts +7 -4
  9. package/dist/cjs/plugins/hedera/HbarPricePlugin.d.ts +7 -35
  10. package/dist/cjs/plugins/index.d.ts +0 -5
  11. package/dist/cjs/plugins/weather/index.d.ts +6 -5
  12. package/dist/cjs/standards-agent-kit.cjs +1 -1
  13. package/dist/cjs/standards-agent-kit.cjs.map +1 -1
  14. package/dist/cjs/state/state-types.d.ts +8 -8
  15. package/dist/cjs/tools/hcs10/AcceptConnectionRequestTool.d.ts +40 -0
  16. package/dist/cjs/tools/hcs10/CheckMessagesTool.d.ts +40 -0
  17. package/dist/cjs/tools/hcs10/ConnectionMonitorTool.d.ts +134 -0
  18. package/dist/cjs/tools/hcs10/FindRegistrationsTool.d.ts +34 -0
  19. package/dist/cjs/tools/hcs10/InitiateConnectionTool.d.ts +43 -0
  20. package/dist/cjs/tools/hcs10/ListConnectionsTool.d.ts +34 -0
  21. package/dist/cjs/tools/hcs10/ListUnapprovedConnectionRequestsTool.d.ts +15 -0
  22. package/dist/cjs/tools/hcs10/ManageConnectionRequestsTool.d.ts +34 -0
  23. package/dist/cjs/tools/hcs10/RegisterAgentTool.d.ts +218 -0
  24. package/dist/cjs/tools/hcs10/RetrieveProfileTool.d.ts +33 -0
  25. package/dist/cjs/tools/hcs10/SendMessageToConnectionTool.d.ts +40 -0
  26. package/dist/cjs/tools/hcs10/base-hcs10-tools.d.ts +28 -0
  27. package/dist/cjs/tools/hcs10/hcs10-tool-params.d.ts +18 -0
  28. package/dist/cjs/tools/hcs10/index.d.ts +13 -0
  29. package/dist/cjs/tools/index.d.ts +1 -13
  30. package/dist/es/builders/hcs10/hcs10-builder.d.ts +262 -0
  31. package/dist/es/builders/index.d.ts +2 -0
  32. package/dist/es/builders/types.d.ts +10 -0
  33. package/dist/es/index.d.ts +3 -1
  34. package/dist/es/init/init.d.ts +21 -22
  35. package/dist/es/plugins/PluginInterface.d.ts +4 -80
  36. package/dist/es/plugins/PluginRegistry.d.ts +1 -47
  37. package/dist/es/plugins/defi/index.d.ts +7 -4
  38. package/dist/es/plugins/hedera/HbarPricePlugin.d.ts +7 -35
  39. package/dist/es/plugins/index.d.ts +0 -5
  40. package/dist/es/plugins/weather/index.d.ts +6 -5
  41. package/dist/es/standards-agent-kit.es.js +10 -18
  42. package/dist/es/standards-agent-kit.es.js.map +1 -1
  43. package/dist/es/standards-agent-kit.es10.js +29 -76
  44. package/dist/es/standards-agent-kit.es10.js.map +1 -1
  45. package/dist/es/standards-agent-kit.es11.js +61 -384
  46. package/dist/es/standards-agent-kit.es11.js.map +1 -1
  47. package/dist/es/standards-agent-kit.es12.js +22 -190
  48. package/dist/es/standards-agent-kit.es12.js.map +1 -1
  49. package/dist/es/standards-agent-kit.es13.js +26 -138
  50. package/dist/es/standards-agent-kit.es13.js.map +1 -1
  51. package/dist/es/standards-agent-kit.es14.js +35 -59
  52. package/dist/es/standards-agent-kit.es14.js.map +1 -1
  53. package/dist/es/standards-agent-kit.es15.js +11 -117
  54. package/dist/es/standards-agent-kit.es15.js.map +1 -1
  55. package/dist/es/standards-agent-kit.es16.js +1 -1
  56. package/dist/es/standards-agent-kit.es16.js.map +1 -1
  57. package/dist/es/standards-agent-kit.es17.js +63 -46
  58. package/dist/es/standards-agent-kit.es17.js.map +1 -1
  59. package/dist/es/standards-agent-kit.es18.js +25 -74
  60. package/dist/es/standards-agent-kit.es18.js.map +1 -1
  61. package/dist/es/standards-agent-kit.es19.js +22 -13
  62. package/dist/es/standards-agent-kit.es19.js.map +1 -1
  63. package/dist/es/standards-agent-kit.es2.js +1381 -188
  64. package/dist/es/standards-agent-kit.es2.js.map +1 -1
  65. package/dist/es/standards-agent-kit.es20.js +3 -67
  66. package/dist/es/standards-agent-kit.es20.js.map +1 -1
  67. package/dist/es/standards-agent-kit.es3.js +285 -347
  68. package/dist/es/standards-agent-kit.es3.js.map +1 -1
  69. package/dist/es/standards-agent-kit.es4.js +22 -74
  70. package/dist/es/standards-agent-kit.es4.js.map +1 -1
  71. package/dist/es/standards-agent-kit.es5.js +127 -154
  72. package/dist/es/standards-agent-kit.es5.js.map +1 -1
  73. package/dist/es/standards-agent-kit.es6.js +21 -88
  74. package/dist/es/standards-agent-kit.es6.js.map +1 -1
  75. package/dist/es/standards-agent-kit.es7.js +28 -86
  76. package/dist/es/standards-agent-kit.es7.js.map +1 -1
  77. package/dist/es/standards-agent-kit.es8.js +27 -100
  78. package/dist/es/standards-agent-kit.es8.js.map +1 -1
  79. package/dist/es/standards-agent-kit.es9.js +35 -117
  80. package/dist/es/standards-agent-kit.es9.js.map +1 -1
  81. package/dist/es/state/state-types.d.ts +8 -8
  82. package/dist/es/tools/hcs10/AcceptConnectionRequestTool.d.ts +40 -0
  83. package/dist/es/tools/hcs10/CheckMessagesTool.d.ts +40 -0
  84. package/dist/es/tools/hcs10/ConnectionMonitorTool.d.ts +134 -0
  85. package/dist/es/tools/hcs10/FindRegistrationsTool.d.ts +34 -0
  86. package/dist/es/tools/hcs10/InitiateConnectionTool.d.ts +43 -0
  87. package/dist/es/tools/hcs10/ListConnectionsTool.d.ts +34 -0
  88. package/dist/es/tools/hcs10/ListUnapprovedConnectionRequestsTool.d.ts +15 -0
  89. package/dist/es/tools/hcs10/ManageConnectionRequestsTool.d.ts +34 -0
  90. package/dist/es/tools/hcs10/RegisterAgentTool.d.ts +218 -0
  91. package/dist/es/tools/hcs10/RetrieveProfileTool.d.ts +33 -0
  92. package/dist/es/tools/hcs10/SendMessageToConnectionTool.d.ts +40 -0
  93. package/dist/es/tools/hcs10/base-hcs10-tools.d.ts +28 -0
  94. package/dist/es/tools/hcs10/hcs10-tool-params.d.ts +18 -0
  95. package/dist/es/tools/hcs10/index.d.ts +13 -0
  96. package/dist/es/tools/index.d.ts +1 -13
  97. package/dist/umd/builders/hcs10/hcs10-builder.d.ts +262 -0
  98. package/dist/umd/builders/index.d.ts +2 -0
  99. package/dist/umd/builders/types.d.ts +10 -0
  100. package/dist/umd/index.d.ts +3 -1
  101. package/dist/umd/init/init.d.ts +21 -22
  102. package/dist/umd/plugins/PluginInterface.d.ts +4 -80
  103. package/dist/umd/plugins/PluginRegistry.d.ts +1 -47
  104. package/dist/umd/plugins/defi/index.d.ts +7 -4
  105. package/dist/umd/plugins/hedera/HbarPricePlugin.d.ts +7 -35
  106. package/dist/umd/plugins/index.d.ts +0 -5
  107. package/dist/umd/plugins/weather/index.d.ts +6 -5
  108. package/dist/umd/standards-agent-kit.umd.js +1 -164
  109. package/dist/umd/standards-agent-kit.umd.js.map +1 -1
  110. package/dist/umd/state/state-types.d.ts +8 -8
  111. package/dist/umd/tools/hcs10/AcceptConnectionRequestTool.d.ts +40 -0
  112. package/dist/umd/tools/hcs10/CheckMessagesTool.d.ts +40 -0
  113. package/dist/umd/tools/hcs10/ConnectionMonitorTool.d.ts +134 -0
  114. package/dist/umd/tools/hcs10/FindRegistrationsTool.d.ts +34 -0
  115. package/dist/umd/tools/hcs10/InitiateConnectionTool.d.ts +43 -0
  116. package/dist/umd/tools/hcs10/ListConnectionsTool.d.ts +34 -0
  117. package/dist/umd/tools/hcs10/ListUnapprovedConnectionRequestsTool.d.ts +15 -0
  118. package/dist/umd/tools/hcs10/ManageConnectionRequestsTool.d.ts +34 -0
  119. package/dist/umd/tools/hcs10/RegisterAgentTool.d.ts +218 -0
  120. package/dist/umd/tools/hcs10/RetrieveProfileTool.d.ts +33 -0
  121. package/dist/umd/tools/hcs10/SendMessageToConnectionTool.d.ts +40 -0
  122. package/dist/umd/tools/hcs10/base-hcs10-tools.d.ts +28 -0
  123. package/dist/umd/tools/hcs10/hcs10-tool-params.d.ts +18 -0
  124. package/dist/umd/tools/hcs10/index.d.ts +13 -0
  125. package/dist/umd/tools/index.d.ts +1 -13
  126. package/package.json +41 -41
  127. package/src/builders/hcs10/hcs10-builder.ts +2108 -0
  128. package/src/builders/index.ts +2 -0
  129. package/src/builders/types.ts +11 -0
  130. package/src/hcs10/HCS10Client.ts +3 -2
  131. package/src/index.ts +4 -2
  132. package/src/init/init.ts +85 -63
  133. package/src/plugins/PluginInterface.ts +15 -94
  134. package/src/plugins/PluginRegistry.ts +2 -98
  135. package/src/plugins/defi/index.ts +31 -118
  136. package/src/plugins/hedera/HbarPricePlugin.ts +19 -100
  137. package/src/plugins/index.ts +0 -5
  138. package/src/plugins/weather/index.ts +56 -40
  139. package/src/state/state-types.ts +9 -11
  140. package/src/tools/hcs10/AcceptConnectionRequestTool.ts +56 -0
  141. package/src/tools/hcs10/CheckMessagesTool.ts +73 -0
  142. package/src/tools/hcs10/ConnectionMonitorTool.ts +111 -0
  143. package/src/tools/hcs10/FindRegistrationsTool.ts +64 -0
  144. package/src/tools/hcs10/InitiateConnectionTool.ts +66 -0
  145. package/src/tools/hcs10/ListConnectionsTool.ts +58 -0
  146. package/src/tools/hcs10/ListUnapprovedConnectionRequestsTool.ts +26 -0
  147. package/src/tools/hcs10/ManageConnectionRequestsTool.ts +48 -0
  148. package/src/tools/hcs10/RegisterAgentTool.ts +213 -0
  149. package/src/tools/hcs10/RetrieveProfileTool.ts +61 -0
  150. package/src/tools/hcs10/SendMessageToConnectionTool.ts +45 -0
  151. package/src/tools/hcs10/base-hcs10-tools.ts +65 -0
  152. package/src/tools/hcs10/hcs10-tool-params.ts +21 -0
  153. package/src/tools/hcs10/index.ts +13 -0
  154. package/src/tools/index.ts +2 -13
  155. package/src/utils/HederaClient.ts +2 -2
  156. package/src/utils/ensure-agent-has-hbar.ts +3 -4
  157. package/dist/cjs/agents/index.d.ts +0 -0
  158. package/dist/cjs/plugins/BasePlugin.d.ts +0 -28
  159. package/dist/cjs/plugins/GenericPlugin.d.ts +0 -17
  160. package/dist/cjs/plugins/HCS10Plugin.d.ts +0 -13
  161. package/dist/cjs/plugins/PluginLoader.d.ts +0 -38
  162. package/dist/cjs/plugins/openconvai/OpenConvAIPlugin.d.ts +0 -23
  163. package/dist/cjs/plugins/openconvai/index.d.ts +0 -1
  164. package/dist/cjs/tools/AcceptConnectionRequestTool.d.ts +0 -33
  165. package/dist/cjs/tools/CheckMessagesTool.d.ts +0 -34
  166. package/dist/cjs/tools/ConnectionMonitorTool.d.ts +0 -100
  167. package/dist/cjs/tools/ConnectionTool.d.ts +0 -40
  168. package/dist/cjs/tools/FindRegistrationsTool.d.ts +0 -28
  169. package/dist/cjs/tools/InitiateConnectionTool.d.ts +0 -30
  170. package/dist/cjs/tools/ListConnectionsTool.d.ts +0 -33
  171. package/dist/cjs/tools/ListUnapprovedConnectionRequestsTool.d.ts +0 -41
  172. package/dist/cjs/tools/ManageConnectionRequestsTool.d.ts +0 -38
  173. package/dist/cjs/tools/RegisterAgentTool.d.ts +0 -188
  174. package/dist/cjs/tools/RetrieveProfileTool.d.ts +0 -34
  175. package/dist/cjs/tools/SendMessageToConnectionTool.d.ts +0 -34
  176. package/dist/cjs/tools/SendMessageTool.d.ts +0 -40
  177. package/dist/es/agents/index.d.ts +0 -0
  178. package/dist/es/plugins/BasePlugin.d.ts +0 -28
  179. package/dist/es/plugins/GenericPlugin.d.ts +0 -17
  180. package/dist/es/plugins/HCS10Plugin.d.ts +0 -13
  181. package/dist/es/plugins/PluginLoader.d.ts +0 -38
  182. package/dist/es/plugins/openconvai/OpenConvAIPlugin.d.ts +0 -23
  183. package/dist/es/plugins/openconvai/index.d.ts +0 -1
  184. package/dist/es/standards-agent-kit.es21.js +0 -92
  185. package/dist/es/standards-agent-kit.es21.js.map +0 -1
  186. package/dist/es/standards-agent-kit.es22.js +0 -7
  187. package/dist/es/standards-agent-kit.es22.js.map +0 -1
  188. package/dist/es/standards-agent-kit.es23.js +0 -106
  189. package/dist/es/standards-agent-kit.es23.js.map +0 -1
  190. package/dist/es/standards-agent-kit.es24.js +0 -7
  191. package/dist/es/standards-agent-kit.es24.js.map +0 -1
  192. package/dist/es/standards-agent-kit.es25.js +0 -7
  193. package/dist/es/standards-agent-kit.es25.js.map +0 -1
  194. package/dist/es/standards-agent-kit.es26.js +0 -85
  195. package/dist/es/standards-agent-kit.es26.js.map +0 -1
  196. package/dist/es/standards-agent-kit.es27.js +0 -28
  197. package/dist/es/standards-agent-kit.es27.js.map +0 -1
  198. package/dist/es/tools/AcceptConnectionRequestTool.d.ts +0 -33
  199. package/dist/es/tools/CheckMessagesTool.d.ts +0 -34
  200. package/dist/es/tools/ConnectionMonitorTool.d.ts +0 -100
  201. package/dist/es/tools/ConnectionTool.d.ts +0 -40
  202. package/dist/es/tools/FindRegistrationsTool.d.ts +0 -28
  203. package/dist/es/tools/InitiateConnectionTool.d.ts +0 -30
  204. package/dist/es/tools/ListConnectionsTool.d.ts +0 -33
  205. package/dist/es/tools/ListUnapprovedConnectionRequestsTool.d.ts +0 -41
  206. package/dist/es/tools/ManageConnectionRequestsTool.d.ts +0 -38
  207. package/dist/es/tools/RegisterAgentTool.d.ts +0 -188
  208. package/dist/es/tools/RetrieveProfileTool.d.ts +0 -34
  209. package/dist/es/tools/SendMessageToConnectionTool.d.ts +0 -34
  210. package/dist/es/tools/SendMessageTool.d.ts +0 -40
  211. package/dist/umd/agents/index.d.ts +0 -0
  212. package/dist/umd/plugins/BasePlugin.d.ts +0 -28
  213. package/dist/umd/plugins/GenericPlugin.d.ts +0 -17
  214. package/dist/umd/plugins/HCS10Plugin.d.ts +0 -13
  215. package/dist/umd/plugins/PluginLoader.d.ts +0 -38
  216. package/dist/umd/plugins/openconvai/OpenConvAIPlugin.d.ts +0 -23
  217. package/dist/umd/plugins/openconvai/index.d.ts +0 -1
  218. package/dist/umd/tools/AcceptConnectionRequestTool.d.ts +0 -33
  219. package/dist/umd/tools/CheckMessagesTool.d.ts +0 -34
  220. package/dist/umd/tools/ConnectionMonitorTool.d.ts +0 -100
  221. package/dist/umd/tools/ConnectionTool.d.ts +0 -40
  222. package/dist/umd/tools/FindRegistrationsTool.d.ts +0 -28
  223. package/dist/umd/tools/InitiateConnectionTool.d.ts +0 -30
  224. package/dist/umd/tools/ListConnectionsTool.d.ts +0 -33
  225. package/dist/umd/tools/ListUnapprovedConnectionRequestsTool.d.ts +0 -41
  226. package/dist/umd/tools/ManageConnectionRequestsTool.d.ts +0 -38
  227. package/dist/umd/tools/RegisterAgentTool.d.ts +0 -188
  228. package/dist/umd/tools/RetrieveProfileTool.d.ts +0 -34
  229. package/dist/umd/tools/SendMessageToConnectionTool.d.ts +0 -34
  230. package/dist/umd/tools/SendMessageTool.d.ts +0 -40
  231. package/src/agents/index.ts +0 -1
  232. package/src/plugins/BasePlugin.ts +0 -37
  233. package/src/plugins/GenericPlugin.ts +0 -19
  234. package/src/plugins/HCS10Plugin.ts +0 -14
  235. package/src/plugins/PluginLoader.ts +0 -121
  236. package/src/plugins/README.md +0 -113
  237. package/src/plugins/openconvai/OpenConvAIPlugin.ts +0 -124
  238. package/src/plugins/openconvai/index.ts +0 -1
  239. package/src/tools/AcceptConnectionRequestTool.ts +0 -196
  240. package/src/tools/CheckMessagesTool.ts +0 -194
  241. package/src/tools/ConnectionMonitorTool.ts +0 -550
  242. package/src/tools/ConnectionTool.ts +0 -231
  243. package/src/tools/FindRegistrationsTool.ts +0 -114
  244. package/src/tools/InitiateConnectionTool.ts +0 -137
  245. package/src/tools/ListConnectionsTool.ts +0 -158
  246. package/src/tools/ListUnapprovedConnectionRequestsTool.ts +0 -173
  247. package/src/tools/ManageConnectionRequestsTool.ts +0 -275
  248. package/src/tools/RegisterAgentTool.ts +0 -590
  249. package/src/tools/RetrieveProfileTool.ts +0 -94
  250. package/src/tools/SendMessageToConnectionTool.ts +0 -142
  251. package/src/tools/SendMessageTool.ts +0 -116
@@ -0,0 +1,2108 @@
1
+ import { BaseServiceBuilder } from 'hedera-agent-kit';
2
+ import type { HederaAgentKit } from 'hedera-agent-kit';
3
+ import { PrivateKey, TransactionReceipt } from '@hashgraph/sdk';
4
+ import { ActiveConnection, IStateManager } from '../../state/state-types';
5
+ import { ExecuteResult } from '../types';
6
+ import {
7
+ FeeConfigBuilderInterface,
8
+ FeeConfigBuilder,
9
+ HCS10Client,
10
+ AgentBuilder,
11
+ InboundTopicType as StandardInboundTopicType,
12
+ AIAgentCapability as StandardAIAgentCapability,
13
+ AgentRegistrationResult,
14
+ ProfileResponse as SDKProfileResponse,
15
+ HCSMessage,
16
+ LogLevel,
17
+ Logger as SDKLogger,
18
+ SocialPlatform,
19
+ HandleConnectionRequestResponse,
20
+ Connection,
21
+ } from '@hashgraphonline/standards-sdk';
22
+ import fs from 'fs';
23
+ import path from 'path';
24
+ import axios from 'axios';
25
+
26
+ const NOT_INITIALIZED_ERROR = 'ConnectionsManager not initialized';
27
+
28
+ /**
29
+ * Internal agent data for registration
30
+ */
31
+ interface AgentRegistrationData {
32
+ name: string;
33
+ bio?: string;
34
+ alias?: string;
35
+ type?: 'autonomous' | 'manual';
36
+ model?: string;
37
+ capabilities?: number[];
38
+ creator?: string;
39
+ socials?: Record<string, string>;
40
+ properties?: Record<string, unknown>;
41
+ pfpBuffer?: Buffer;
42
+ pfpFileName?: string;
43
+ existingProfilePictureTopicId?: string;
44
+ feeConfig?: FeeConfigBuilderInterface;
45
+ }
46
+
47
+ /**
48
+ * Message response with timestamp
49
+ */
50
+ export interface HCSMessageWithTimestamp extends Omit<HCSMessage, 'op'> {
51
+ timestamp: number;
52
+ data?: string;
53
+ sequence_number: number;
54
+ op?: HCSMessage['op'] | string;
55
+ operator_id?: string;
56
+ created?: Date;
57
+ m?: string;
58
+ }
59
+
60
+ /**
61
+ * Network type for HCS-10
62
+ */
63
+ export type StandardNetworkType = 'mainnet' | 'testnet';
64
+
65
+ /**
66
+ * Parameters for agent registration
67
+ */
68
+ export interface RegisterAgentParams {
69
+ name: string;
70
+ bio?: string;
71
+ alias?: string;
72
+ type?: 'autonomous' | 'manual';
73
+ model?: string;
74
+ capabilities?: number[];
75
+ creator?: string;
76
+ socials?: Record<string, string>;
77
+ properties?: Record<string, unknown>;
78
+ profilePicture?:
79
+ | string
80
+ | {
81
+ url?: string;
82
+ path?: string;
83
+ filename?: string;
84
+ };
85
+ existingProfilePictureTopicId?: string;
86
+ initialBalance?: number;
87
+ userAccountId?: string;
88
+ hbarFee?: number;
89
+ tokenFees?: Array<{
90
+ amount: number;
91
+ tokenId: string;
92
+ }>;
93
+ exemptAccountIds?: string[];
94
+ }
95
+
96
+ /**
97
+ * Parameters for initiating a connection
98
+ */
99
+ export interface InitiateConnectionParams {
100
+ targetAccountId: string;
101
+ disableMonitor?: boolean;
102
+ memo?: string;
103
+ }
104
+
105
+ /**
106
+ * Parameters for accepting a connection request
107
+ */
108
+ export interface AcceptConnectionParams {
109
+ requestKey: string;
110
+ hbarFee?: number | undefined;
111
+ exemptAccountIds?: string[] | undefined;
112
+ }
113
+
114
+ /**
115
+ * Parameters for sending a message
116
+ */
117
+ export interface SendMessageParams {
118
+ topicId: string;
119
+ message: string;
120
+ disableMonitoring?: boolean;
121
+ }
122
+
123
+ /**
124
+ * Parameters for sending a message to a connected account
125
+ */
126
+ export interface SendMessageToConnectionParams {
127
+ targetIdentifier: string;
128
+ message: string;
129
+ disableMonitoring?: boolean;
130
+ }
131
+
132
+ /**
133
+ * HCS10Builder facilitates HCS-10 protocol operations for agent communication
134
+ * This builder incorporates all HCS10Client functionality directly
135
+ */
136
+ export class HCS10Builder extends BaseServiceBuilder {
137
+ private standardClient: HCS10Client;
138
+ private stateManager: IStateManager | undefined;
139
+ private executeResult?: ExecuteResult & { rawResult?: unknown };
140
+ private useEncryption: boolean;
141
+ private guardedRegistryBaseUrl: string;
142
+ private network: StandardNetworkType;
143
+ private sdkLogger: SDKLogger;
144
+
145
+ constructor(
146
+ hederaKit: HederaAgentKit,
147
+ stateManager?: IStateManager,
148
+ options?: {
149
+ useEncryption?: boolean;
150
+ registryUrl?: string;
151
+ logLevel?: LogLevel;
152
+ }
153
+ ) {
154
+ super(hederaKit);
155
+ this.stateManager = stateManager;
156
+ this.useEncryption = options?.useEncryption || false;
157
+ this.guardedRegistryBaseUrl = options?.registryUrl || '';
158
+
159
+ const network = this.hederaKit.client.network;
160
+ this.network = network.toString().includes('mainnet')
161
+ ? 'mainnet'
162
+ : 'testnet';
163
+
164
+ const operatorId = this.hederaKit.signer.getAccountId().toString();
165
+ const operatorPrivateKey = this.hederaKit.signer?.getOperatorPrivateKey()
166
+ ? this.hederaKit.signer.getOperatorPrivateKey().toStringRaw()
167
+ : '';
168
+
169
+ this.sdkLogger = new SDKLogger({
170
+ module: 'HCS10Builder',
171
+ level: options?.logLevel || 'info',
172
+ });
173
+
174
+ this.standardClient = new HCS10Client({
175
+ network: this.network,
176
+ operatorId: operatorId,
177
+ operatorPrivateKey: operatorPrivateKey,
178
+ guardedRegistryBaseUrl: this.guardedRegistryBaseUrl,
179
+ logLevel: options?.logLevel || 'info',
180
+ });
181
+
182
+ if (this.stateManager) {
183
+ this.stateManager.initializeConnectionsManager(this.standardClient);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Get the operator account ID
189
+ */
190
+ public getOperatorId(): string {
191
+ const operator = this.standardClient.getClient().operatorAccountId;
192
+ if (!operator) {
193
+ throw new Error('Operator Account ID not configured in standard client.');
194
+ }
195
+ return operator.toString();
196
+ }
197
+
198
+ /**
199
+ * Get the network type
200
+ */
201
+ public getNetwork(): StandardNetworkType {
202
+ return this.network;
203
+ }
204
+
205
+ /**
206
+ * Get account and signer information
207
+ */
208
+ public getAccountAndSigner(): { accountId: string; signer: PrivateKey } {
209
+ const result = this.standardClient.getAccountAndSigner();
210
+ return {
211
+ accountId: result.accountId,
212
+ signer: result.signer as unknown as PrivateKey,
213
+ };
214
+ }
215
+
216
+ /**
217
+ * Get the inbound topic ID for the current operator
218
+ */
219
+ public async getInboundTopicId(): Promise<string> {
220
+ try {
221
+ const operatorId = this.getOperatorId();
222
+ this.logger.info(
223
+ `[HCS10Builder] Retrieving profile for operator ${operatorId} to find inbound topic...`
224
+ );
225
+ const profileResponse = await this.getAgentProfile(operatorId);
226
+ if (profileResponse.success && profileResponse.topicInfo?.inboundTopic) {
227
+ this.logger.info(
228
+ `[HCS10Builder] Found inbound topic for operator ${operatorId}: ${profileResponse.topicInfo.inboundTopic}`
229
+ );
230
+ return profileResponse.topicInfo.inboundTopic;
231
+ } else {
232
+ throw new Error(
233
+ `Could not retrieve inbound topic from profile for ${operatorId}. Profile success: ${profileResponse.success}, Error: ${profileResponse.error}`
234
+ );
235
+ }
236
+ } catch (error) {
237
+ this.logger.error(
238
+ `[HCS10Builder] Error fetching operator's inbound topic ID (${this.getOperatorId()}):`,
239
+ error
240
+ );
241
+ const operatorId = this.getOperatorId();
242
+ let detailedMessage = `Failed to get inbound topic ID for operator ${operatorId}.`;
243
+ if (
244
+ error instanceof Error &&
245
+ error.message.includes('does not have a valid HCS-11 memo')
246
+ ) {
247
+ detailedMessage += ` The account profile may not exist or is invalid. Please ensure this operator account (${operatorId}) is registered as an HCS-10 agent. You might need to register it first (e.g., using the 'register_agent' tool or SDK function).`;
248
+ } else if (error instanceof Error) {
249
+ detailedMessage += ` Reason: ${error.message}`;
250
+ } else {
251
+ detailedMessage += ` Unexpected error: ${String(error)}`;
252
+ }
253
+ throw new Error(detailedMessage);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Get agent profile
259
+ */
260
+ public async getAgentProfile(accountId: string): Promise<SDKProfileResponse> {
261
+ try {
262
+ return await this.standardClient.retrieveProfile(accountId);
263
+ } catch (error) {
264
+ this.logger.error(
265
+ `[HCS10Builder] Error retrieving agent profile for account ${accountId}:`,
266
+ error
267
+ );
268
+ throw error;
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Submit connection request
274
+ */
275
+ public async submitConnectionRequest(
276
+ inboundTopicId: string,
277
+ memo: string
278
+ ): Promise<TransactionReceipt> {
279
+ return this.standardClient.submitConnectionRequest(
280
+ inboundTopicId,
281
+ memo
282
+ ) as Promise<TransactionReceipt>;
283
+ }
284
+
285
+ /**
286
+ * Handle connection request
287
+ */
288
+ public async handleConnectionRequest(
289
+ inboundTopicId: string,
290
+ requestingAccountId: string,
291
+ connectionRequestId: number,
292
+ feeConfig?: FeeConfigBuilderInterface
293
+ ): Promise<HandleConnectionRequestResponse> {
294
+ try {
295
+ const result = await this.standardClient.handleConnectionRequest(
296
+ inboundTopicId,
297
+ requestingAccountId,
298
+ connectionRequestId,
299
+ feeConfig
300
+ );
301
+
302
+ if (
303
+ result &&
304
+ result.connectionTopicId &&
305
+ typeof result.connectionTopicId === 'object' &&
306
+ 'toString' in result.connectionTopicId
307
+ ) {
308
+ result.connectionTopicId = (
309
+ result.connectionTopicId as { toString(): string }
310
+ ).toString();
311
+ }
312
+
313
+ return result;
314
+ } catch (error) {
315
+ this.logger.error(
316
+ `Error handling connection request #${connectionRequestId} for topic ${inboundTopicId}:`,
317
+ error
318
+ );
319
+ throw new Error(
320
+ `Failed to handle connection request: ${
321
+ error instanceof Error ? error.message : String(error)
322
+ }`
323
+ );
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Send message to a topic
329
+ */
330
+ public async sendMessage(
331
+ topicId: string,
332
+ data: string,
333
+ memo?: string
334
+ ): Promise<{
335
+ sequenceNumber: number | undefined;
336
+ receipt: TransactionReceipt;
337
+ transactionId: string | undefined;
338
+ }> {
339
+ if (topicId && typeof topicId === 'object' && 'toString' in topicId) {
340
+ topicId = (topicId as unknown as { toString: () => string })?.toString();
341
+ }
342
+
343
+ if (!topicId || typeof topicId !== 'string') {
344
+ throw new Error(
345
+ `Invalid topic ID provided to sendMessage: ${JSON.stringify(topicId)}`
346
+ );
347
+ }
348
+
349
+ try {
350
+ const messageResponse = await this.standardClient.sendMessage(
351
+ topicId,
352
+ data,
353
+ memo,
354
+ undefined
355
+ );
356
+ return {
357
+ sequenceNumber: messageResponse.topicSequenceNumber?.toNumber(),
358
+ receipt: messageResponse as unknown as TransactionReceipt,
359
+ transactionId:
360
+ 'transactionId' in messageResponse
361
+ ? (
362
+ messageResponse as { transactionId?: { toString(): string } }
363
+ ).transactionId?.toString()
364
+ : undefined,
365
+ };
366
+ } catch (error) {
367
+ this.logger.error(`Error sending message to topic ${topicId}:`, error);
368
+ throw new Error(
369
+ `Failed to send message: ${
370
+ error instanceof Error ? error.message : String(error)
371
+ }`
372
+ );
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Get messages from a topic
378
+ */
379
+ public async getMessages(topicId: string): Promise<{
380
+ messages: HCSMessageWithTimestamp[];
381
+ }> {
382
+ if (topicId && typeof topicId === 'object' && 'toString' in topicId) {
383
+ topicId = (topicId as unknown as { toString: () => string })?.toString();
384
+ }
385
+
386
+ if (!topicId || typeof topicId !== 'string') {
387
+ throw new Error(
388
+ `Invalid topic ID provided to getMessages: ${JSON.stringify(topicId)}`
389
+ );
390
+ }
391
+
392
+ try {
393
+ const result = await this.standardClient.getMessages(topicId);
394
+
395
+ const mappedMessages: HCSMessageWithTimestamp[] = result.messages.map((sdkMessage) => {
396
+ const timestamp = sdkMessage?.created?.getTime() || 0;
397
+
398
+ return {
399
+ ...sdkMessage,
400
+ timestamp: timestamp,
401
+ data: sdkMessage.data || '',
402
+ sequence_number: sdkMessage.sequence_number,
403
+ p: 'hcs-10' as const,
404
+ } as HCSMessageWithTimestamp;
405
+ });
406
+ mappedMessages.sort(
407
+ (a: { timestamp: number }, b: { timestamp: number }) =>
408
+ a.timestamp - b.timestamp
409
+ );
410
+ return { messages: mappedMessages };
411
+ } catch (error) {
412
+ this.logger.error(`Error getting messages from topic ${topicId}:`, error);
413
+ return { messages: [] };
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Get message stream from a topic
419
+ */
420
+ public async getMessageStream(topicId: string): Promise<{
421
+ messages: HCSMessage[];
422
+ }> {
423
+ if (topicId && typeof topicId === 'object' && 'toString' in topicId) {
424
+ topicId = (topicId as unknown as { toString: () => string })?.toString();
425
+ }
426
+
427
+ if (!topicId || typeof topicId !== 'string') {
428
+ throw new Error(
429
+ `Invalid topic ID provided to getMessageStream: ${JSON.stringify(
430
+ topicId
431
+ )}`
432
+ );
433
+ }
434
+
435
+ return this.standardClient.getMessageStream(topicId) as Promise<{ messages: HCSMessage[] }>;
436
+ }
437
+
438
+ /**
439
+ * Get message content
440
+ */
441
+ public async getMessageContent(inscriptionIdOrData: string): Promise<string> {
442
+ try {
443
+ const content = await this.standardClient.getMessageContent(
444
+ inscriptionIdOrData
445
+ );
446
+ return content as string;
447
+ } catch (error) {
448
+ this.logger.error(
449
+ `Error retrieving message content for: ${inscriptionIdOrData}`,
450
+ error
451
+ );
452
+ throw new Error(
453
+ `Failed to retrieve message content: ${
454
+ error instanceof Error ? error.message : String(error)
455
+ }`
456
+ );
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Get the standard client instance (for compatibility)
462
+ */
463
+ public getStandardClient(): HCS10Client {
464
+ return this.standardClient;
465
+ }
466
+
467
+ /**
468
+ * Load profile picture from URL or file path
469
+ */
470
+ private async loadProfilePicture(
471
+ profilePicture: string | { url?: string; path?: string; filename?: string }
472
+ ): Promise<{ buffer: Buffer; filename: string } | null> {
473
+ try {
474
+ if (!profilePicture) {
475
+ return null;
476
+ }
477
+
478
+ if (typeof profilePicture === 'string') {
479
+ const isUrl =
480
+ profilePicture.startsWith('http://') ||
481
+ profilePicture.startsWith('https://');
482
+
483
+ if (isUrl) {
484
+ this.logger.info(
485
+ `Loading profile picture from URL: ${profilePicture}`
486
+ );
487
+ const response = await axios.get(profilePicture, {
488
+ responseType: 'arraybuffer',
489
+ });
490
+ const buffer = Buffer.from(response.data);
491
+ const urlPathname = new URL(profilePicture).pathname;
492
+ const filename = path.basename(urlPathname) || 'profile.png';
493
+ return { buffer, filename };
494
+ } else {
495
+ if (!fs.existsSync(profilePicture)) {
496
+ this.logger.warn(
497
+ `Profile picture file not found: ${profilePicture}`
498
+ );
499
+ return null;
500
+ }
501
+ this.logger.info(
502
+ `Loading profile picture from file: ${profilePicture}`
503
+ );
504
+ const buffer = fs.readFileSync(profilePicture);
505
+ const filename = path.basename(profilePicture);
506
+ return { buffer, filename };
507
+ }
508
+ } else if (profilePicture.url) {
509
+ this.logger.info(
510
+ `Loading profile picture from URL: ${profilePicture.url}`
511
+ );
512
+ const response = await axios.get(profilePicture.url, {
513
+ responseType: 'arraybuffer',
514
+ });
515
+ const buffer = Buffer.from(response.data);
516
+ const filename = profilePicture.filename || 'profile.png';
517
+ return { buffer, filename };
518
+ } else if (profilePicture.path) {
519
+ if (!fs.existsSync(profilePicture.path)) {
520
+ this.logger.warn(
521
+ `Profile picture file not found: ${profilePicture.path}`
522
+ );
523
+ return null;
524
+ }
525
+ this.logger.info(
526
+ `Loading profile picture from file: ${profilePicture.path}`
527
+ );
528
+ const buffer = fs.readFileSync(profilePicture.path);
529
+ const filename =
530
+ profilePicture.filename || path.basename(profilePicture.path);
531
+ return { buffer, filename };
532
+ }
533
+
534
+ return null;
535
+ } catch (error) {
536
+ this.logger.error('Failed to load profile picture:', error);
537
+ return null;
538
+ }
539
+ }
540
+
541
+ /**
542
+ * Create and register an agent
543
+ */
544
+ private async createAndRegisterAgent(
545
+ data: AgentRegistrationData
546
+ ): Promise<AgentRegistrationResult> {
547
+ const builder = new AgentBuilder()
548
+ .setName(data.name)
549
+ .setBio(data.bio || '')
550
+ .setCapabilities(
551
+ data.capabilities || [StandardAIAgentCapability.TEXT_GENERATION]
552
+ )
553
+ .setType(data.type || 'autonomous')
554
+ .setModel(data.model || 'agent-model-2024')
555
+ .setNetwork(this.getNetwork())
556
+ .setInboundTopicType(StandardInboundTopicType.PUBLIC);
557
+
558
+ if (data.alias) {
559
+ builder.setAlias(data.alias);
560
+ }
561
+
562
+ if (data.creator) {
563
+ builder.setCreator(data.creator);
564
+ }
565
+
566
+ if (data?.feeConfig) {
567
+ builder.setInboundTopicType(StandardInboundTopicType.FEE_BASED);
568
+ builder.setFeeConfig(data.feeConfig);
569
+ }
570
+
571
+ if (data.existingProfilePictureTopicId) {
572
+ builder.setExistingProfilePicture(data.existingProfilePictureTopicId);
573
+ } else if (data.pfpBuffer && data.pfpFileName) {
574
+ if (data.pfpBuffer.byteLength === 0) {
575
+ this.logger.warn(
576
+ 'Provided PFP buffer is empty. Skipping profile picture.'
577
+ );
578
+ } else {
579
+ this.logger.info(
580
+ `Setting profile picture: ${data.pfpFileName} (${data.pfpBuffer.byteLength} bytes)`
581
+ );
582
+ builder.setProfilePicture(data.pfpBuffer, data.pfpFileName);
583
+ }
584
+ } else {
585
+ this.logger.warn(
586
+ 'Profile picture not provided. Agent creation might fail if required by the underlying SDK builder.'
587
+ );
588
+ }
589
+
590
+ if (data.socials) {
591
+ Object.entries(data.socials).forEach(([platform, handle]) => {
592
+ builder.addSocial(platform as SocialPlatform, handle);
593
+ });
594
+ }
595
+
596
+ if (data.properties) {
597
+ Object.entries(data.properties).forEach(([key, value]) => {
598
+ builder.addProperty(key, value);
599
+ });
600
+ }
601
+
602
+ try {
603
+ const hasFees = Boolean(data?.feeConfig);
604
+ const result = await this.standardClient.createAndRegisterAgent(builder, {
605
+ initialBalance: hasFees ? 50 : 10,
606
+ });
607
+ return result;
608
+ } catch (error) {
609
+ this.logger.error('Error during agent creation/registration:', error);
610
+ throw new Error(
611
+ `Failed to create/register agent: ${
612
+ error instanceof Error ? error.message : String(error)
613
+ }`
614
+ );
615
+ }
616
+ }
617
+
618
+ /**
619
+ * Register a new HCS-10 agent
620
+ * Note: This performs multiple transactions and requires directExecution mode
621
+ */
622
+ public async registerAgent(params: RegisterAgentParams): Promise<this> {
623
+ this.clearNotes();
624
+
625
+ if (this.hederaKit.operationalMode === 'returnBytes') {
626
+ throw new Error(
627
+ 'Agent registration requires multiple transactions and cannot be performed in returnBytes mode. ' +
628
+ 'Please use autonomous mode.'
629
+ );
630
+ }
631
+
632
+ try {
633
+ let profilePictureData: { buffer: Buffer; filename: string } | null = null;
634
+ if (params.profilePicture) {
635
+ profilePictureData = await this.loadProfilePicture(
636
+ params.profilePicture
637
+ );
638
+ }
639
+
640
+ const registrationData: AgentRegistrationData = {
641
+ name: params.name,
642
+ ...(params.bio !== undefined && { bio: params.bio }),
643
+ ...(params.alias !== undefined && { alias: params.alias }),
644
+ ...(params.type !== undefined && { type: params.type }),
645
+ ...(params.model !== undefined && { model: params.model }),
646
+ ...(params.capabilities !== undefined && {
647
+ capabilities: params.capabilities,
648
+ }),
649
+ ...(params.creator !== undefined && { creator: params.creator }),
650
+ ...(params.socials !== undefined && { socials: params.socials }),
651
+ ...(params.properties !== undefined && {
652
+ properties: params.properties,
653
+ }),
654
+ ...(params.existingProfilePictureTopicId !== undefined && {
655
+ existingProfilePictureTopicId: params.existingProfilePictureTopicId,
656
+ }),
657
+ ...(profilePictureData?.buffer !== undefined && {
658
+ pfpBuffer: profilePictureData.buffer,
659
+ }),
660
+ ...(profilePictureData?.filename !== undefined && {
661
+ pfpFileName: profilePictureData.filename,
662
+ }),
663
+ };
664
+
665
+ if (params.hbarFee && params.hbarFee > 0) {
666
+ const feeConfigBuilder = new FeeConfigBuilder({
667
+ network: this.network,
668
+ logger: this.sdkLogger,
669
+ });
670
+
671
+ const { accountId: collectorAccountId } = this.getAccountAndSigner();
672
+ if (!collectorAccountId) {
673
+ throw new Error('Could not determine account ID for fee collection.');
674
+ }
675
+ this.addNote(
676
+ `Setting the operator account (${collectorAccountId}) as the fee collector since no specific collector was provided.`
677
+ );
678
+
679
+ const effectiveExemptIds =
680
+ params.exemptAccountIds?.filter(
681
+ (id: string) => id !== collectorAccountId && id.startsWith('0.0')
682
+ ) || [];
683
+
684
+ registrationData.feeConfig = feeConfigBuilder.addHbarFee(
685
+ params.hbarFee,
686
+ collectorAccountId,
687
+ effectiveExemptIds
688
+ );
689
+ }
690
+
691
+ const result = await this.createAndRegisterAgent(registrationData);
692
+
693
+ this.executeResult = {
694
+ success: true,
695
+ transactionId: result.transactionId,
696
+ receipt: undefined,
697
+ scheduleId: undefined,
698
+ rawResult: {
699
+ ...result,
700
+ name: params.name,
701
+ accountId:
702
+ result?.metadata?.accountId ||
703
+ result.state?.agentMetadata?.accountId,
704
+ },
705
+ } as unknown as ExecuteResult & { rawResult?: unknown };
706
+ } catch (error) {
707
+ this.logger.error('Failed to register agent:', error);
708
+ throw error;
709
+ }
710
+
711
+ return this;
712
+ }
713
+
714
+ /**
715
+ * Initiate a connection to another agent
716
+ */
717
+ public async initiateConnection(
718
+ params: InitiateConnectionParams
719
+ ): Promise<this> {
720
+ this.clearNotes();
721
+
722
+ try {
723
+ const targetProfile = await this.getAgentProfile(params.targetAccountId);
724
+
725
+ if (!targetProfile.success || !targetProfile.topicInfo?.inboundTopic) {
726
+ throw new Error(
727
+ `Could not retrieve inbound topic for target account ${params.targetAccountId}`
728
+ );
729
+ }
730
+
731
+ const targetInboundTopicId = targetProfile.topicInfo.inboundTopic;
732
+ let memo: string;
733
+ if (params.memo !== undefined) {
734
+ memo = params.memo;
735
+ } else {
736
+ memo = params.disableMonitor ? 'false' : 'true';
737
+ this.addNote(
738
+ `No custom memo was provided. Using default memo '${memo}' based on monitoring preference.`
739
+ );
740
+ }
741
+ if (!params.disableMonitor) {
742
+ this.addNote(
743
+ `Monitoring will be enabled for this connection request as disableMonitor was not specified.`
744
+ );
745
+ }
746
+
747
+ const result = await this.submitConnectionRequest(
748
+ targetInboundTopicId,
749
+ memo
750
+ );
751
+
752
+ this.executeResult = {
753
+ success: true,
754
+ transactionId:
755
+ 'transactionId' in result
756
+ ? (
757
+ result as { transactionId?: { toString(): string } }
758
+ ).transactionId?.toString()
759
+ : undefined,
760
+ receipt: result,
761
+ scheduleId: undefined,
762
+ rawResult: {
763
+ targetAccountId: params.targetAccountId,
764
+ targetInboundTopicId,
765
+ connectionRequestSent: true,
766
+ monitoringEnabled: !params.disableMonitor,
767
+ ...result,
768
+ },
769
+ } as unknown as ExecuteResult & { rawResult?: unknown };
770
+ } catch (error) {
771
+ this.logger.error('Failed to initiate connection:', error);
772
+ throw error;
773
+ }
774
+
775
+ return this;
776
+ }
777
+
778
+ /**
779
+ * Accept a connection request
780
+ * Note: This performs multiple transactions and requires directExecution mode
781
+ */
782
+ public async acceptConnection(params: AcceptConnectionParams): Promise<this> {
783
+ this.clearNotes();
784
+
785
+ if (this.hederaKit.operationalMode === 'returnBytes') {
786
+ throw new Error(
787
+ 'Accepting connections requires multiple transactions and cannot be performed in returnBytes mode. ' +
788
+ 'Please use autonomous mode.'
789
+ );
790
+ }
791
+
792
+ try {
793
+ const currentAgent = this.stateManager?.getCurrentAgent();
794
+ if (!currentAgent) {
795
+ throw new Error(
796
+ 'Cannot accept connection request. No agent is currently active. Please register or select an agent first.'
797
+ );
798
+ }
799
+
800
+ const connectionsManager = this.stateManager?.getConnectionsManager();
801
+ if (!connectionsManager) {
802
+ throw new Error(NOT_INITIALIZED_ERROR);
803
+ }
804
+
805
+ await connectionsManager.fetchConnectionData(currentAgent.accountId);
806
+
807
+ const allRequests = [
808
+ ...connectionsManager.getPendingRequests(),
809
+ ...connectionsManager.getConnectionsNeedingConfirmation(),
810
+ ];
811
+
812
+ const request = allRequests.find(
813
+ (r) =>
814
+ r.uniqueRequestKey === params.requestKey ||
815
+ r.connectionRequestId?.toString() === params.requestKey ||
816
+ r.inboundRequestId?.toString() === params.requestKey
817
+ );
818
+
819
+ if (!request) {
820
+ throw new Error(
821
+ `Request with key ${params.requestKey} not found or no longer pending.`
822
+ );
823
+ }
824
+
825
+ if (!request.needsConfirmation || !request.inboundRequestId) {
826
+ throw new Error(
827
+ `Request with key ${params.requestKey} is not an inbound request that can be accepted.`
828
+ );
829
+ }
830
+
831
+ const targetAccountId = request.targetAccountId;
832
+ const inboundRequestId = request.inboundRequestId;
833
+
834
+ let feeConfig: FeeConfigBuilderInterface | undefined;
835
+
836
+ if (params.hbarFee && params.hbarFee > 0) {
837
+ const feeConfigBuilder = new FeeConfigBuilder({
838
+ network: this.network,
839
+ logger: this.sdkLogger,
840
+ });
841
+
842
+ const { accountId: collectorAccountId } = this.getAccountAndSigner();
843
+ if (!collectorAccountId) {
844
+ throw new Error('Could not determine account ID for fee collection.');
845
+ }
846
+ this.addNote(
847
+ `Setting the operator account (${collectorAccountId}) as the fee collector since no specific collector was provided.`
848
+ );
849
+
850
+ const effectiveExemptIds =
851
+ params.exemptAccountIds?.filter(
852
+ (id: string) => id !== collectorAccountId && id.startsWith('0.0')
853
+ ) || [];
854
+
855
+ feeConfig = feeConfigBuilder.addHbarFee(
856
+ params.hbarFee,
857
+ collectorAccountId,
858
+ effectiveExemptIds
859
+ );
860
+ }
861
+
862
+ const inboundTopicId = await this.getInboundTopicId();
863
+ const confirmationResult = await this.handleConnectionRequest(
864
+ inboundTopicId,
865
+ targetAccountId,
866
+ inboundRequestId,
867
+ feeConfig
868
+ );
869
+
870
+ let connectionTopicId = confirmationResult?.connectionTopicId;
871
+
872
+ if (
873
+ connectionTopicId &&
874
+ typeof connectionTopicId === 'object' &&
875
+ 'toString' in connectionTopicId
876
+ ) {
877
+ connectionTopicId = (
878
+ connectionTopicId as unknown as { toString: () => string }
879
+ )?.toString();
880
+ }
881
+
882
+ if (!connectionTopicId || typeof connectionTopicId !== 'string') {
883
+ throw new Error(
884
+ `Failed to create connection topic. Got: ${JSON.stringify(
885
+ connectionTopicId
886
+ )}`
887
+ );
888
+ }
889
+
890
+ if (this.stateManager) {
891
+ const targetAgentName =
892
+ request.targetAgentName || `Agent ${targetAccountId}`;
893
+ if (!request.targetAgentName) {
894
+ this.addNote(
895
+ `No agent name was provided in the connection request, using default name 'Agent ${targetAccountId}'.`
896
+ );
897
+ }
898
+
899
+ let targetInboundTopicId = request.targetInboundTopicId || '';
900
+ if (!targetInboundTopicId) {
901
+ try {
902
+ const targetProfile = await this.getAgentProfile(targetAccountId);
903
+ if (
904
+ targetProfile.success &&
905
+ targetProfile.topicInfo?.inboundTopic
906
+ ) {
907
+ targetInboundTopicId = targetProfile.topicInfo.inboundTopic;
908
+ }
909
+ } catch (profileError) {
910
+ this.logger.warn(
911
+ `Could not fetch profile for ${targetAccountId}:`,
912
+ profileError
913
+ );
914
+ }
915
+ }
916
+
917
+ const newConnection = {
918
+ connectionId: `conn-${Date.now()}`,
919
+ targetAccountId: targetAccountId,
920
+ targetAgentName: targetAgentName,
921
+ targetInboundTopicId: targetInboundTopicId,
922
+ connectionTopicId: connectionTopicId,
923
+ status: 'established' as const,
924
+ created: new Date(),
925
+ };
926
+ this.stateManager.addActiveConnection(newConnection);
927
+
928
+ connectionsManager.markConnectionRequestProcessed(
929
+ request.targetInboundTopicId || '',
930
+ inboundRequestId
931
+ );
932
+ }
933
+
934
+ this.executeResult = {
935
+ success: true,
936
+ transactionId: undefined,
937
+ receipt: undefined,
938
+ scheduleId: undefined,
939
+ rawResult: {
940
+ targetAccountId,
941
+ connectionTopicId,
942
+ feeConfigured: !!params.hbarFee,
943
+ hbarFee: params.hbarFee || 0,
944
+ confirmationResult,
945
+ },
946
+ } as unknown as ExecuteResult & { rawResult?: unknown };
947
+ } catch (error) {
948
+ this.logger.error('Failed to accept connection:', error);
949
+ throw error;
950
+ }
951
+
952
+ return this;
953
+ }
954
+
955
+ /**
956
+ * Send a message using HCS (for operations that need direct topic access)
957
+ */
958
+ public async sendHCS10Message(params: SendMessageParams): Promise<this> {
959
+ this.clearNotes();
960
+
961
+ try {
962
+ const result = await this.sendMessage(params.topicId, params.message);
963
+
964
+ this.executeResult = {
965
+ success: true,
966
+ transactionId: result.transactionId,
967
+ receipt: result.receipt,
968
+ scheduleId: undefined,
969
+ rawResult: result,
970
+ } as unknown as ExecuteResult & { rawResult?: unknown };
971
+
972
+ this.addNote(`Message sent to topic ${params.topicId}.`);
973
+ } catch (error) {
974
+ this.logger.error('Failed to send message:', error);
975
+ throw error;
976
+ }
977
+
978
+ return this;
979
+ }
980
+
981
+ /**
982
+ * Send a message to a connected account with optional response monitoring
983
+ */
984
+ public async sendMessageToConnection(
985
+ params: SendMessageToConnectionParams
986
+ ): Promise<this> {
987
+ this.clearNotes();
988
+
989
+ if (!this.stateManager) {
990
+ throw new Error(
991
+ 'StateManager is required to send messages to connections'
992
+ );
993
+ }
994
+
995
+ try {
996
+ const currentAgent = this.stateManager.getCurrentAgent();
997
+ if (!currentAgent) {
998
+ throw new Error(
999
+ 'Cannot send message. No agent is currently active. Please register or select an agent first.'
1000
+ );
1001
+ }
1002
+
1003
+ let connection: ActiveConnection | undefined;
1004
+
1005
+ if (params.targetIdentifier.includes('@')) {
1006
+ const parts = params.targetIdentifier.split('@');
1007
+ if (parts.length === 2) {
1008
+ const accountId = parts[1];
1009
+ connection = this.stateManager.getConnectionByIdentifier(accountId);
1010
+
1011
+ if (!connection) {
1012
+ this.addNote(
1013
+ `Could not find connection using request key '${params.targetIdentifier}', extracted account ID '${accountId}'.`
1014
+ );
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ if (!connection) {
1020
+ connection = this.stateManager.getConnectionByIdentifier(
1021
+ params.targetIdentifier
1022
+ );
1023
+ }
1024
+
1025
+ if (!connection) {
1026
+ const connections = this.stateManager.listConnections();
1027
+ const availableIds = connections.map(
1028
+ (c) => `${c.targetAccountId} (${c.connectionTopicId})`
1029
+ );
1030
+ throw new Error(
1031
+ `Connection not found for identifier: ${
1032
+ params.targetIdentifier
1033
+ }. Available connections: ${
1034
+ availableIds.join(', ') || 'none'
1035
+ }. Use 'list_connections' to see details.`
1036
+ );
1037
+ }
1038
+
1039
+ let connectionTopicId = connection.connectionTopicId;
1040
+ if (
1041
+ connectionTopicId &&
1042
+ typeof connectionTopicId === 'object' &&
1043
+ 'toString' in connectionTopicId
1044
+ ) {
1045
+ connectionTopicId = (
1046
+ connectionTopicId as unknown as { toString: () => string }
1047
+ )?.toString();
1048
+ }
1049
+
1050
+ if (!connectionTopicId || typeof connectionTopicId !== 'string') {
1051
+ throw new Error(
1052
+ `Invalid connection topic ID for ${
1053
+ connection.targetAccountId
1054
+ }: ${JSON.stringify(
1055
+ connectionTopicId
1056
+ )} (type: ${typeof connectionTopicId})`
1057
+ );
1058
+ }
1059
+
1060
+ const targetAgentName = connection.targetAgentName;
1061
+
1062
+ const operatorId = `${currentAgent.inboundTopicId}@${currentAgent.accountId}`;
1063
+
1064
+ const messageResult = await this.sendMessage(
1065
+ connectionTopicId,
1066
+ params.message,
1067
+ `Agent message from ${currentAgent.name}`
1068
+ );
1069
+
1070
+ if (!messageResult.sequenceNumber) {
1071
+ throw new Error('Failed to send message');
1072
+ }
1073
+
1074
+ let reply: string | null = null;
1075
+ if (!params.disableMonitoring) {
1076
+ reply = await this.monitorResponses(
1077
+ connectionTopicId,
1078
+ operatorId,
1079
+ messageResult.sequenceNumber
1080
+ );
1081
+ } else {
1082
+ this.addNote(
1083
+ `Message sent successfully. Response monitoring was disabled.`
1084
+ );
1085
+ }
1086
+
1087
+ this.executeResult = {
1088
+ success: true,
1089
+ transactionId: messageResult.transactionId,
1090
+ receipt: messageResult.receipt,
1091
+ scheduleId: undefined,
1092
+ rawResult: {
1093
+ targetAgentName,
1094
+ targetAccountId: connection.targetAccountId,
1095
+ connectionTopicId,
1096
+ sequenceNumber: messageResult.sequenceNumber,
1097
+ reply,
1098
+ monitoringEnabled: !params.disableMonitoring,
1099
+ message: params.message,
1100
+ messageResult,
1101
+ },
1102
+ };
1103
+ } catch (error) {
1104
+ this.logger.error('Failed to send message to connection:', error);
1105
+ throw error;
1106
+ }
1107
+
1108
+ return this;
1109
+ }
1110
+
1111
+ /**
1112
+ * Monitor responses on a topic after sending a message
1113
+ */
1114
+ private async monitorResponses(
1115
+ topicId: string,
1116
+ operatorId: string,
1117
+ sequenceNumber: number
1118
+ ): Promise<string | null> {
1119
+ const maxAttempts = 30;
1120
+ let attempts = 0;
1121
+
1122
+ while (attempts < maxAttempts) {
1123
+ try {
1124
+ const messages = await this.getMessageStream(topicId);
1125
+
1126
+ for (const message of messages.messages) {
1127
+ if (
1128
+ message.sequence_number < sequenceNumber ||
1129
+ message.operator_id === operatorId
1130
+ ) {
1131
+ continue;
1132
+ }
1133
+ const content = await this.getMessageContent(message.data || '');
1134
+ return content;
1135
+ }
1136
+ } catch (error) {
1137
+ this.logger.error(`Error monitoring responses: ${error}`);
1138
+ }
1139
+ await new Promise((resolve) => setTimeout(resolve, 4000));
1140
+ attempts++;
1141
+ }
1142
+ return null;
1143
+ }
1144
+
1145
+ /**
1146
+ * Start passive monitoring for incoming connection requests
1147
+ * This method monitors continuously in the background
1148
+ */
1149
+ public async startPassiveConnectionMonitoring(): Promise<this> {
1150
+ this.clearNotes();
1151
+
1152
+ if (!this.stateManager) {
1153
+ throw new Error('StateManager is required for passive monitoring');
1154
+ }
1155
+
1156
+ const inboundTopicId = await this.getInboundTopicId();
1157
+ this.logger.info(
1158
+ `Starting passive connection monitoring on topic ${inboundTopicId}...`
1159
+ );
1160
+
1161
+ this.executeResult = {
1162
+ success: true,
1163
+ transactionId: undefined,
1164
+ receipt: undefined,
1165
+ scheduleId: undefined,
1166
+ rawResult: {
1167
+ inboundTopicId,
1168
+ message: `Started monitoring inbound topic ${inboundTopicId} for connection requests in the background.`,
1169
+ },
1170
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1171
+
1172
+ return this;
1173
+ }
1174
+
1175
+ /**
1176
+ * Monitor for incoming connection requests
1177
+ */
1178
+ public async monitorConnections(params: {
1179
+ acceptAll?: boolean;
1180
+ targetAccountId?: string;
1181
+ monitorDurationSeconds?: number;
1182
+ hbarFees?: Array<{ amount: number; collectorAccount?: string }>;
1183
+ tokenFees?: Array<{
1184
+ amount: number;
1185
+ tokenId: string;
1186
+ collectorAccount?: string;
1187
+ }>;
1188
+ exemptAccountIds?: string[];
1189
+ defaultCollectorAccount?: string;
1190
+ }): Promise<this> {
1191
+ this.clearNotes();
1192
+
1193
+ const {
1194
+ acceptAll = false,
1195
+ targetAccountId,
1196
+ monitorDurationSeconds = 120,
1197
+ hbarFees = [],
1198
+ tokenFees = [],
1199
+ exemptAccountIds = [],
1200
+ defaultCollectorAccount,
1201
+ } = params;
1202
+
1203
+ if (!this.stateManager) {
1204
+ throw new Error('StateManager is required for connection monitoring');
1205
+ }
1206
+
1207
+ const currentAgent = this.stateManager.getCurrentAgent();
1208
+ if (!currentAgent) {
1209
+ throw new Error(
1210
+ 'Cannot monitor for connections. No agent is currently active.'
1211
+ );
1212
+ }
1213
+
1214
+ const inboundTopicId = await this.getInboundTopicId();
1215
+ const endTime = Date.now() + monitorDurationSeconds * 1000;
1216
+ const pollIntervalMs = 3000;
1217
+ let connectionRequestsFound = 0;
1218
+ let acceptedConnections = 0;
1219
+ const processedRequestIds = new Set<number>();
1220
+
1221
+ while (Date.now() < endTime) {
1222
+ try {
1223
+ const messagesResult = await this.getMessages(inboundTopicId);
1224
+ const connectionRequests = messagesResult.messages.filter(
1225
+ (msg) =>
1226
+ msg.op === 'connection_request' &&
1227
+ typeof msg.sequence_number === 'number'
1228
+ );
1229
+
1230
+ for (const request of connectionRequests) {
1231
+ const connectionRequestId = request.sequence_number;
1232
+ if (
1233
+ !connectionRequestId ||
1234
+ processedRequestIds.has(connectionRequestId)
1235
+ ) {
1236
+ continue;
1237
+ }
1238
+
1239
+ const requestingAccountId = request.operator_id?.split('@')[1];
1240
+ if (!requestingAccountId) {
1241
+ continue;
1242
+ }
1243
+
1244
+ connectionRequestsFound++;
1245
+
1246
+ if (targetAccountId && requestingAccountId !== targetAccountId) {
1247
+ this.logger.info(
1248
+ `Skipping request from ${requestingAccountId} (not target account)`
1249
+ );
1250
+ continue;
1251
+ }
1252
+
1253
+ if (acceptAll || targetAccountId === requestingAccountId) {
1254
+ this.logger.info(
1255
+ `Accepting connection request from ${requestingAccountId}`
1256
+ );
1257
+
1258
+ let feeConfig;
1259
+ if (hbarFees.length > 0 || tokenFees.length > 0) {
1260
+ const builder = new FeeConfigBuilder({
1261
+ network: this.network,
1262
+ logger: this.sdkLogger,
1263
+ });
1264
+
1265
+ for (const fee of hbarFees) {
1266
+ const collectorAccount =
1267
+ fee.collectorAccount ||
1268
+ defaultCollectorAccount ||
1269
+ this.getOperatorId();
1270
+ builder.addHbarFee(
1271
+ fee.amount,
1272
+ collectorAccount,
1273
+ exemptAccountIds
1274
+ );
1275
+ }
1276
+
1277
+ for (const fee of tokenFees) {
1278
+ const collectorAccount =
1279
+ fee.collectorAccount ||
1280
+ defaultCollectorAccount ||
1281
+ this.getOperatorId();
1282
+ builder.addTokenFee(
1283
+ fee.amount,
1284
+ fee.tokenId,
1285
+ collectorAccount,
1286
+ undefined,
1287
+ exemptAccountIds
1288
+ );
1289
+ }
1290
+
1291
+ feeConfig = builder;
1292
+ }
1293
+
1294
+ await this.handleConnectionRequest(
1295
+ inboundTopicId,
1296
+ requestingAccountId,
1297
+ connectionRequestId,
1298
+ feeConfig
1299
+ );
1300
+
1301
+ processedRequestIds.add(connectionRequestId);
1302
+ acceptedConnections++;
1303
+ }
1304
+ }
1305
+ } catch (error) {
1306
+ this.logger.error('Error during connection monitoring:', error);
1307
+ }
1308
+
1309
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
1310
+ }
1311
+
1312
+ this.executeResult = {
1313
+ success: true,
1314
+ transactionId: undefined,
1315
+ receipt: undefined,
1316
+ scheduleId: undefined,
1317
+ rawResult: {
1318
+ connectionRequestsFound,
1319
+ acceptedConnections,
1320
+ monitorDurationSeconds,
1321
+ processedRequestIds: Array.from(processedRequestIds),
1322
+ },
1323
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1324
+
1325
+ this.addNote(
1326
+ `Monitoring completed. Found ${connectionRequestsFound} requests, accepted ${acceptedConnections}.`
1327
+ );
1328
+
1329
+ return this;
1330
+ }
1331
+
1332
+ /**
1333
+ * Manage connection requests (list, view, or reject)
1334
+ */
1335
+ public async manageConnectionRequests(params: {
1336
+ action: 'list' | 'view' | 'reject';
1337
+ requestKey?: string;
1338
+ }): Promise<this> {
1339
+ this.clearNotes();
1340
+
1341
+ if (!this.stateManager) {
1342
+ throw new Error(
1343
+ 'StateManager is required for managing connection requests'
1344
+ );
1345
+ }
1346
+
1347
+ const currentAgent = this.stateManager.getCurrentAgent();
1348
+ if (!currentAgent) {
1349
+ throw new Error(
1350
+ 'Cannot manage connection requests. No agent is currently active.'
1351
+ );
1352
+ }
1353
+
1354
+ const connectionsManager = this.stateManager.getConnectionsManager();
1355
+ if (!connectionsManager) {
1356
+ throw new Error(NOT_INITIALIZED_ERROR);
1357
+ }
1358
+
1359
+ try {
1360
+ const { accountId } = this.getAccountAndSigner();
1361
+ await connectionsManager.fetchConnectionData(accountId);
1362
+
1363
+ const pendingRequests = connectionsManager.getPendingRequests();
1364
+ const needsConfirmation =
1365
+ connectionsManager.getConnectionsNeedingConfirmation();
1366
+ const allRequests = [...pendingRequests, ...needsConfirmation];
1367
+
1368
+ switch (params.action) {
1369
+ case 'list':
1370
+ this.executeResult = {
1371
+ success: true,
1372
+ transactionId: undefined,
1373
+ receipt: undefined,
1374
+ scheduleId: undefined,
1375
+ rawResult: {
1376
+ requests: allRequests.map((request, index) => ({
1377
+ index: index + 1,
1378
+ type: request.needsConfirmation ? 'incoming' : 'outgoing',
1379
+ requestKey:
1380
+ request.uniqueRequestKey ||
1381
+ `${
1382
+ request.connectionRequestId ||
1383
+ request.inboundRequestId ||
1384
+ 'unknown'
1385
+ }`,
1386
+ targetAccountId: request.targetAccountId,
1387
+ targetAgentName:
1388
+ request.targetAgentName || `Agent ${request.targetAccountId}`,
1389
+ created: request.created.toISOString(),
1390
+ memo: request.memo,
1391
+ bio: request.profileInfo?.bio,
1392
+ })),
1393
+ },
1394
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1395
+ break;
1396
+
1397
+ case 'view': {
1398
+ if (!params.requestKey) {
1399
+ throw new Error('Request key is required for viewing a request');
1400
+ }
1401
+ const viewRequest = allRequests.find(
1402
+ (r) =>
1403
+ r.uniqueRequestKey === params.requestKey ||
1404
+ r.connectionRequestId?.toString() === params.requestKey ||
1405
+ r.inboundRequestId?.toString() === params.requestKey
1406
+ );
1407
+ if (!viewRequest) {
1408
+ throw new Error(`Request with key ${params.requestKey} not found`);
1409
+ }
1410
+ this.executeResult = {
1411
+ success: true,
1412
+ transactionId: undefined,
1413
+ receipt: undefined,
1414
+ scheduleId: undefined,
1415
+ rawResult: {
1416
+ request: {
1417
+ type: viewRequest.needsConfirmation ? 'incoming' : 'outgoing',
1418
+ requestKey:
1419
+ viewRequest.uniqueRequestKey ||
1420
+ `${
1421
+ viewRequest.connectionRequestId ||
1422
+ viewRequest.inboundRequestId ||
1423
+ 'unknown'
1424
+ }`,
1425
+ targetAccountId: viewRequest.targetAccountId,
1426
+ targetAgentName:
1427
+ viewRequest.targetAgentName ||
1428
+ `Agent ${viewRequest.targetAccountId}`,
1429
+ created: viewRequest.created.toISOString(),
1430
+ memo: viewRequest.memo,
1431
+ profileInfo: viewRequest.profileInfo,
1432
+ },
1433
+ },
1434
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1435
+ break;
1436
+ }
1437
+
1438
+ case 'reject': {
1439
+ if (!params.requestKey) {
1440
+ throw new Error('Request key is required for rejecting a request');
1441
+ }
1442
+ const rejectRequest = allRequests.find(
1443
+ (r) =>
1444
+ r.uniqueRequestKey === params.requestKey ||
1445
+ r.connectionRequestId?.toString() === params.requestKey ||
1446
+ r.inboundRequestId?.toString() === params.requestKey
1447
+ );
1448
+ if (!rejectRequest) {
1449
+ throw new Error(`Request with key ${params.requestKey} not found`);
1450
+ }
1451
+ if (rejectRequest.inboundRequestId) {
1452
+ connectionsManager.markConnectionRequestProcessed(
1453
+ rejectRequest.targetInboundTopicId || '',
1454
+ rejectRequest.inboundRequestId
1455
+ );
1456
+ } else if (rejectRequest.connectionRequestId) {
1457
+ connectionsManager.markConnectionRequestProcessed(
1458
+ rejectRequest.originTopicId || '',
1459
+ rejectRequest.connectionRequestId
1460
+ );
1461
+ }
1462
+ this.executeResult = {
1463
+ success: true,
1464
+ transactionId: undefined,
1465
+ receipt: undefined,
1466
+ scheduleId: undefined,
1467
+ rawResult: {
1468
+ rejectedRequest: {
1469
+ requestKey: params.requestKey,
1470
+ targetAccountId: rejectRequest.targetAccountId,
1471
+ targetAgentName:
1472
+ rejectRequest.targetAgentName ||
1473
+ `Agent ${rejectRequest.targetAccountId}`,
1474
+ },
1475
+ },
1476
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1477
+ break;
1478
+ }
1479
+ }
1480
+ } catch (error) {
1481
+ this.logger.error('Failed to manage connection requests:', error);
1482
+ throw error;
1483
+ }
1484
+
1485
+ return this;
1486
+ }
1487
+
1488
+ /**
1489
+ * List unapproved connection requests
1490
+ */
1491
+ public async listUnapprovedConnectionRequests(): Promise<this> {
1492
+ this.clearNotes();
1493
+
1494
+ if (!this.stateManager) {
1495
+ throw new Error(
1496
+ 'StateManager is required for listing connection requests'
1497
+ );
1498
+ }
1499
+
1500
+ const currentAgent = this.stateManager.getCurrentAgent();
1501
+ if (!currentAgent) {
1502
+ throw new Error(
1503
+ 'Cannot list connection requests. No agent is currently active.'
1504
+ );
1505
+ }
1506
+
1507
+ try {
1508
+ const inboundTopicId = await this.getInboundTopicId();
1509
+ const messages = await this.getMessages(inboundTopicId);
1510
+
1511
+ const unapprovedRequests = messages.messages
1512
+ .filter((msg): msg is HCSMessageWithTimestamp & { op: string } => msg.op === 'connection_request')
1513
+ .map((msg) => ({
1514
+ requestId: msg.sequence_number,
1515
+ fromAccountId: msg.operator_id?.split('@')[1] || 'unknown',
1516
+ timestamp: msg.timestamp || new Date(msg?.created || '').getTime(),
1517
+ memo: msg.m || '',
1518
+ data: msg.data,
1519
+ }))
1520
+ .filter((req): req is typeof req & { fromAccountId: string } => req.fromAccountId !== 'unknown');
1521
+
1522
+ this.executeResult = {
1523
+ success: true,
1524
+ transactionId: undefined,
1525
+ receipt: undefined,
1526
+ scheduleId: undefined,
1527
+ rawResult: {
1528
+ requests: unapprovedRequests,
1529
+ count: unapprovedRequests.length,
1530
+ },
1531
+ } as unknown as ExecuteResult & { rawResult?: unknown };
1532
+
1533
+ if (unapprovedRequests.length === 0) {
1534
+ this.addNote('No unapproved connection requests found.');
1535
+ } else {
1536
+ this.addNote(
1537
+ `Found ${unapprovedRequests.length} unapproved connection request(s).`
1538
+ );
1539
+ }
1540
+ } catch (error) {
1541
+ this.logger.error(
1542
+ 'Failed to list unapproved connection requests:',
1543
+ error
1544
+ );
1545
+ throw error;
1546
+ }
1547
+
1548
+ return this;
1549
+ }
1550
+
1551
+ /**
1552
+ * List connections with enhanced details
1553
+ */
1554
+ public async listConnections(
1555
+ params: {
1556
+ includeDetails?: boolean;
1557
+ showPending?: boolean;
1558
+ } = {}
1559
+ ): Promise<this> {
1560
+ this.clearNotes();
1561
+
1562
+ if (!this.stateManager) {
1563
+ throw new Error('StateManager is required to list connections');
1564
+ }
1565
+
1566
+ const includeDetails = params.includeDetails ?? true;
1567
+ const showPending = params.showPending ?? true;
1568
+
1569
+ try {
1570
+ const connections = await this.getEnhancedConnections();
1571
+
1572
+ if (connections.length === 0) {
1573
+ this.executeResult = {
1574
+ success: true,
1575
+ rawResult: {
1576
+ connections: [],
1577
+ message: 'There are currently no active connections.',
1578
+ },
1579
+ } as ExecuteResult & { rawResult?: unknown };
1580
+ return this;
1581
+ }
1582
+
1583
+ const activeConnections = connections.filter(
1584
+ (c): c is Connection => (c as Connection).status === 'established'
1585
+ );
1586
+ const pendingConnections = connections.filter(
1587
+ (c): c is Connection => (c as Connection).isPending
1588
+ );
1589
+ const needsConfirmation = connections.filter(
1590
+ (c): c is Connection => (c as Connection).needsConfirmation
1591
+ );
1592
+
1593
+ let output = '';
1594
+
1595
+ if (activeConnections.length > 0) {
1596
+ output += `🟢 Active Connections (${activeConnections.length}):\n`;
1597
+ activeConnections.forEach((conn, index) => {
1598
+ output += this.formatConnection(conn, index, includeDetails);
1599
+ });
1600
+ output += '\n';
1601
+ }
1602
+
1603
+ if (showPending && needsConfirmation.length > 0) {
1604
+ output += `🟠 Connections Needing Confirmation (${needsConfirmation.length}):\n`;
1605
+ needsConfirmation.forEach((conn, index) => {
1606
+ output += this.formatConnection(conn, index, includeDetails);
1607
+ });
1608
+ output += '\n';
1609
+ }
1610
+
1611
+ if (showPending && pendingConnections.length > 0) {
1612
+ output += `⚪ Pending Connection Requests (${pendingConnections.length}):\n`;
1613
+ pendingConnections.forEach((conn, index) => {
1614
+ output += this.formatConnection(conn, index, includeDetails);
1615
+ });
1616
+ }
1617
+
1618
+ this.executeResult = {
1619
+ success: true,
1620
+ rawResult: {
1621
+ connections,
1622
+ formattedOutput: output.trim(),
1623
+ activeCount: activeConnections.length,
1624
+ pendingCount: pendingConnections.length,
1625
+ needsConfirmationCount: needsConfirmation.length,
1626
+ },
1627
+ } as ExecuteResult & { rawResult?: unknown };
1628
+ } catch (error) {
1629
+ this.logger.error('Failed to list connections:', error);
1630
+ this.executeResult = {
1631
+ success: false,
1632
+ error: `Failed to list connections: ${
1633
+ error instanceof Error ? error.message : String(error)
1634
+ }`,
1635
+ } as ExecuteResult & { rawResult?: unknown };
1636
+ }
1637
+
1638
+ return this;
1639
+ }
1640
+
1641
+ private formatConnection(
1642
+ conn: unknown,
1643
+ index: number,
1644
+ includeDetails: boolean
1645
+ ): string {
1646
+ const connection = conn as {
1647
+ profileInfo?: { display_name?: string; bio?: string };
1648
+ targetAgentName?: string;
1649
+ targetAccountId?: string;
1650
+ isPending?: boolean;
1651
+ connectionTopicId?: string;
1652
+ status?: string;
1653
+ created?: Date;
1654
+ lastActivity?: Date;
1655
+ };
1656
+
1657
+ let output = `${index + 1}. ${
1658
+ connection.profileInfo?.display_name ||
1659
+ connection.targetAgentName ||
1660
+ 'Unknown Agent'
1661
+ } (${connection.targetAccountId})\n`;
1662
+ const displayTopicId = connection.isPending
1663
+ ? '(Pending Request)'
1664
+ : connection.connectionTopicId;
1665
+ output += ` Topic: ${displayTopicId}\n`;
1666
+ const statusText = connection.status || 'unknown';
1667
+ output += ` Status: ${statusText}\n`;
1668
+
1669
+ if (includeDetails) {
1670
+ if (connection.profileInfo?.bio) {
1671
+ output += ` Bio: ${connection.profileInfo.bio.substring(0, 100)}${
1672
+ connection.profileInfo.bio.length > 100 ? '...' : ''
1673
+ }\n`;
1674
+ }
1675
+
1676
+ if (connection.created) {
1677
+ const createdLabel = connection.isPending
1678
+ ? 'Request sent'
1679
+ : 'Connection established';
1680
+ output += ` ${createdLabel}: ${connection.created.toLocaleString()}\n`;
1681
+ }
1682
+
1683
+ if (connection.lastActivity) {
1684
+ output += ` Last activity: ${connection.lastActivity.toLocaleString()}\n`;
1685
+ }
1686
+ }
1687
+
1688
+ return output;
1689
+ }
1690
+
1691
+ private async getEnhancedConnections(): Promise<unknown[]> {
1692
+ try {
1693
+ const { accountId } = this.getAccountAndSigner();
1694
+ if (!accountId) {
1695
+ return this.stateManager!.listConnections();
1696
+ }
1697
+
1698
+ const connectionManager = this.stateManager!.getConnectionsManager();
1699
+ if (!connectionManager) {
1700
+ this.logger.error(NOT_INITIALIZED_ERROR);
1701
+ return this.stateManager!.listConnections();
1702
+ }
1703
+
1704
+ const connections = await connectionManager.fetchConnectionData(
1705
+ accountId
1706
+ );
1707
+
1708
+ for (const connection of connections) {
1709
+ this.stateManager!.addActiveConnection(
1710
+ connection as unknown as ActiveConnection
1711
+ );
1712
+ }
1713
+
1714
+ return connections;
1715
+ } catch (error) {
1716
+ this.logger.error('Failed to get enhanced connections:', error);
1717
+ return this.stateManager!.listConnections();
1718
+ }
1719
+ }
1720
+
1721
+ /**
1722
+ * Check messages on a connection
1723
+ */
1724
+ public async checkMessages(params: {
1725
+ targetIdentifier: string;
1726
+ fetchLatest?: boolean;
1727
+ lastMessagesCount?: number;
1728
+ }): Promise<this> {
1729
+ this.clearNotes();
1730
+
1731
+ if (!this.stateManager) {
1732
+ throw new Error('StateManager is required to check messages');
1733
+ }
1734
+
1735
+ const connection = this.stateManager.getConnectionByIdentifier(
1736
+ params.targetIdentifier
1737
+ );
1738
+
1739
+ if (!connection) {
1740
+ this.executeResult = {
1741
+ success: false,
1742
+ error: `Could not find an active connection matching identifier "${params.targetIdentifier}". Use 'list_connections' to see active connections.`,
1743
+ } as ExecuteResult & { rawResult?: unknown };
1744
+ return this;
1745
+ }
1746
+
1747
+ const connectionTopicId = connection.connectionTopicId || '';
1748
+
1749
+ if (!connectionTopicId || !connectionTopicId.match(/^\d+\.\d+\.\d+$/)) {
1750
+ this.logger.error(
1751
+ `Invalid connection topic ID format: ${connectionTopicId}`
1752
+ );
1753
+ this.executeResult = {
1754
+ success: false,
1755
+ error: `Invalid connection topic ID format: ${connectionTopicId}. Expected format: 0.0.XXXXX`,
1756
+ } as ExecuteResult & { rawResult?: unknown };
1757
+ return this;
1758
+ }
1759
+
1760
+ const targetAgentName = connection.targetAgentName;
1761
+ const lastProcessedTimestamp =
1762
+ this.stateManager.getLastTimestamp(connectionTopicId);
1763
+
1764
+ this.logger.info(
1765
+ `Checking messages for connection with ${targetAgentName} (${connection.targetAccountId}) on topic ${connectionTopicId} (fetchLatest: ${params.fetchLatest}, lastCount: ${params.lastMessagesCount}, since: ${lastProcessedTimestamp})`
1766
+ );
1767
+
1768
+ try {
1769
+ const result = await this.getMessages(connectionTopicId);
1770
+ const allMessages = result.messages;
1771
+
1772
+ if (!allMessages || allMessages.length === 0) {
1773
+ this.executeResult = {
1774
+ success: true,
1775
+ rawResult: {
1776
+ messages: [],
1777
+ message: `No messages found on connection topic ${connectionTopicId}.`,
1778
+ },
1779
+ } as ExecuteResult & { rawResult?: unknown };
1780
+ return this;
1781
+ }
1782
+
1783
+ let messagesToProcess: HCSMessageWithTimestamp[] = [];
1784
+ let latestTimestampNanos = lastProcessedTimestamp;
1785
+ const isFetchingLatest = params.fetchLatest === true;
1786
+
1787
+ if (isFetchingLatest) {
1788
+ this.logger.info('Fetching latest messages regardless of timestamp.');
1789
+ const count = params.lastMessagesCount ?? 1;
1790
+ messagesToProcess = allMessages.slice(-count);
1791
+ } else {
1792
+ this.logger.info(
1793
+ `Filtering for messages newer than ${lastProcessedTimestamp}`
1794
+ );
1795
+ messagesToProcess = allMessages.filter(
1796
+ (msg: HCSMessageWithTimestamp) => {
1797
+ const msgTimestampNanos = msg.timestamp * 1_000_000;
1798
+ return msgTimestampNanos > lastProcessedTimestamp;
1799
+ }
1800
+ );
1801
+
1802
+ if (messagesToProcess.length > 0) {
1803
+ latestTimestampNanos = messagesToProcess.reduce(
1804
+ (maxTs, msg) => Math.max(maxTs, msg.timestamp * 1_000_000),
1805
+ lastProcessedTimestamp
1806
+ );
1807
+ }
1808
+ }
1809
+
1810
+ if (messagesToProcess.length === 0) {
1811
+ const message = isFetchingLatest
1812
+ ? `Could not retrieve the latest message(s). No messages found on topic ${connectionTopicId}.`
1813
+ : `No new messages found for connection with ${targetAgentName} since last check.`;
1814
+
1815
+ this.executeResult = {
1816
+ success: true,
1817
+ rawResult: {
1818
+ messages: [],
1819
+ message,
1820
+ },
1821
+ } as ExecuteResult & { rawResult?: unknown };
1822
+ return this;
1823
+ }
1824
+
1825
+ this.logger.info(`Processing ${messagesToProcess.length} message(s).`);
1826
+
1827
+ let outputString = isFetchingLatest
1828
+ ? `Latest message(s) from ${targetAgentName}:\n`
1829
+ : `New messages from ${targetAgentName}:\n`;
1830
+
1831
+ const processedMessages: Array<{
1832
+ timestamp: number;
1833
+ sequenceNumber: number;
1834
+ content: string | undefined;
1835
+ raw: HCSMessageWithTimestamp;
1836
+ }> = [];
1837
+
1838
+ for (const msg of messagesToProcess) {
1839
+ let content = msg.data;
1840
+ try {
1841
+ if (typeof content === 'string' && content.startsWith('hcs://')) {
1842
+ this.logger.debug(`Resolving inscribed message: ${content}`);
1843
+ content = await this.getMessageContent(content);
1844
+ this.logger.debug(`Resolved content length: ${content?.length}`);
1845
+ }
1846
+
1847
+ let displayContent = content;
1848
+ try {
1849
+ const parsed = JSON.parse(content || '{}');
1850
+ if (
1851
+ parsed.p === 'hcs-10' &&
1852
+ parsed.op === 'message' &&
1853
+ parsed.data
1854
+ ) {
1855
+ const senderOpId = parsed.operator_id || 'unknown_sender';
1856
+ displayContent = `[${senderOpId}]: ${parsed.data}`;
1857
+ } else {
1858
+ displayContent = content;
1859
+ }
1860
+ } catch {
1861
+ displayContent = content;
1862
+ }
1863
+
1864
+ const messageDate = new Date(msg.timestamp);
1865
+ outputString += `\n[${messageDate.toLocaleString()}] (Seq: ${
1866
+ msg.sequence_number
1867
+ })\n${displayContent}\n`;
1868
+
1869
+ processedMessages.push({
1870
+ timestamp: msg.timestamp,
1871
+ sequenceNumber: msg.sequence_number,
1872
+ content: displayContent,
1873
+ raw: msg,
1874
+ });
1875
+ } catch (error) {
1876
+ const errorMsg = `Error processing message (Seq: ${
1877
+ msg.sequence_number
1878
+ }): ${error instanceof Error ? error.message : String(error)}`;
1879
+ this.logger.error(errorMsg);
1880
+ outputString += `\n[Error processing message Seq: ${msg.sequence_number}]\n`;
1881
+ }
1882
+ }
1883
+
1884
+ if (!isFetchingLatest && latestTimestampNanos > lastProcessedTimestamp) {
1885
+ this.logger.debug(
1886
+ `Updating timestamp for topic ${connectionTopicId} to ${latestTimestampNanos}`
1887
+ );
1888
+ this.stateManager.updateTimestamp(
1889
+ connectionTopicId,
1890
+ latestTimestampNanos
1891
+ );
1892
+ }
1893
+
1894
+ this.executeResult = {
1895
+ success: true,
1896
+ rawResult: {
1897
+ messages: processedMessages,
1898
+ formattedOutput: outputString.trim(),
1899
+ targetAgentName,
1900
+ connectionTopicId,
1901
+ },
1902
+ } as ExecuteResult & { rawResult?: unknown };
1903
+ } catch (error) {
1904
+ this.logger.error(
1905
+ `Failed to check messages for topic ${connectionTopicId}: ${error}`
1906
+ );
1907
+ this.executeResult = {
1908
+ success: false,
1909
+ error: `Error checking messages for ${targetAgentName}: ${
1910
+ error instanceof Error ? error.message : String(error)
1911
+ }`,
1912
+ } as ExecuteResult & { rawResult?: unknown };
1913
+ }
1914
+
1915
+ return this;
1916
+ }
1917
+
1918
+ /**
1919
+ * Find registrations using the configured registry
1920
+ */
1921
+ public async findRegistrations(params: {
1922
+ accountId?: string;
1923
+ tags?: number[];
1924
+ }): Promise<this> {
1925
+ this.clearNotes();
1926
+
1927
+ try {
1928
+ const options: {
1929
+ network: StandardNetworkType;
1930
+ accountId?: string;
1931
+ tags?: number[];
1932
+ } = {
1933
+ network: this.network,
1934
+ };
1935
+
1936
+ if (params.accountId) {
1937
+ options.accountId = params.accountId;
1938
+ }
1939
+
1940
+ if (params.tags && params.tags.length > 0) {
1941
+ options.tags = params.tags;
1942
+ }
1943
+
1944
+ const result = await this.standardClient.findRegistrations(options);
1945
+
1946
+ if (!result.success || result.error) {
1947
+ this.executeResult = {
1948
+ success: false,
1949
+ error: `Error finding registrations: ${
1950
+ result.error || 'Unknown error'
1951
+ }`,
1952
+ } as ExecuteResult & { rawResult?: unknown };
1953
+ return this;
1954
+ }
1955
+
1956
+ if (!result.registrations || result.registrations.length === 0) {
1957
+ this.executeResult = {
1958
+ success: true,
1959
+ rawResult: {
1960
+ registrations: [],
1961
+ message: 'No registrations found matching the criteria.',
1962
+ },
1963
+ } as ExecuteResult & { rawResult?: unknown };
1964
+ return this;
1965
+ }
1966
+
1967
+ const formattedRegistrations = result.registrations
1968
+ .map((reg: unknown): string => {
1969
+ const registration = reg as {
1970
+ agent?: { name?: string; capabilities?: string[] };
1971
+ accountId?: string;
1972
+ };
1973
+ const agentName = registration.agent?.name || 'Unknown Agent';
1974
+ const accountId = registration.accountId || 'Unknown Account';
1975
+ const capabilities =
1976
+ registration.agent?.capabilities?.join(', ') || 'None';
1977
+
1978
+ return `Agent: ${agentName} (${accountId}), Capabilities: ${capabilities}`;
1979
+ })
1980
+ .join('\\n');
1981
+
1982
+ this.executeResult = {
1983
+ success: true,
1984
+ rawResult: {
1985
+ registrations: result.registrations,
1986
+ formattedOutput: `Found ${result.registrations.length} registration(s):\\n${formattedRegistrations}`,
1987
+ },
1988
+ } as ExecuteResult & { rawResult?: unknown };
1989
+ } catch (error) {
1990
+ this.logger.error('Error during FindRegistrations execution:', error);
1991
+ this.executeResult = {
1992
+ success: false,
1993
+ error: `Failed to search registrations: ${
1994
+ error instanceof Error ? error.message : String(error)
1995
+ }`,
1996
+ } as ExecuteResult & { rawResult?: unknown };
1997
+ }
1998
+
1999
+ return this;
2000
+ }
2001
+
2002
+ /**
2003
+ * Retrieve detailed profile information for an agent
2004
+ */
2005
+ public async retrieveProfile(params: {
2006
+ accountId: string;
2007
+ disableCache?: boolean;
2008
+ }): Promise<this> {
2009
+ this.clearNotes();
2010
+
2011
+ try {
2012
+ const profileResponse = await this.standardClient.retrieveProfile(
2013
+ params.accountId,
2014
+ params.disableCache || false
2015
+ );
2016
+
2017
+ if (!profileResponse.success) {
2018
+ this.executeResult = {
2019
+ success: false,
2020
+ error: `Failed to retrieve profile: ${
2021
+ profileResponse.error || 'Unknown error'
2022
+ }`,
2023
+ } as ExecuteResult & { rawResult?: unknown };
2024
+ return this;
2025
+ }
2026
+
2027
+ const profile = profileResponse.profile;
2028
+ const topicInfo = profileResponse.topicInfo;
2029
+
2030
+ let profileDetails = `Profile for ${params.accountId}:\n`;
2031
+ profileDetails += `Name: ${profile.name || 'Unknown'}\n`;
2032
+ profileDetails += `Bio: ${profile.bio || 'No bio provided'}\n`;
2033
+ profileDetails += `Type: ${profile.type || 'Unknown'}\n`;
2034
+ profileDetails += `Model: ${profile.model || 'Unknown'}\n`;
2035
+
2036
+ if (profile.capabilities && profile.capabilities.length > 0) {
2037
+ profileDetails += `Capabilities: ${profile.capabilities.join(', ')}\n`;
2038
+ } else {
2039
+ profileDetails += `Capabilities: None listed\n`;
2040
+ }
2041
+
2042
+ if (topicInfo) {
2043
+ profileDetails += `Inbound Topic: ${
2044
+ topicInfo.inboundTopic || 'Unknown'
2045
+ }\n`;
2046
+ profileDetails += `Outbound Topic: ${
2047
+ topicInfo.outboundTopic || 'Unknown'
2048
+ }\n`;
2049
+ profileDetails += `Profile Topic: ${
2050
+ topicInfo.profileTopicId || 'Unknown'
2051
+ }\n`;
2052
+ }
2053
+
2054
+ if (profile.social && Object.keys(profile.social).length > 0) {
2055
+ profileDetails += `Social: ${Object.entries(profile.social)
2056
+ .map(([platform, handle]: [string, unknown]): string => `${platform}: ${handle}`)
2057
+ .join(', ')}\n`;
2058
+ }
2059
+
2060
+ if (profile.properties && Object.keys(profile.properties).length > 0) {
2061
+ profileDetails += `Properties: ${JSON.stringify(profile.properties)}\n`;
2062
+ }
2063
+
2064
+ this.executeResult = {
2065
+ success: true,
2066
+ rawResult: {
2067
+ profileDetails,
2068
+ rawProfile: profileResponse,
2069
+ },
2070
+ } as ExecuteResult & { rawResult?: unknown };
2071
+ } catch (error) {
2072
+ this.logger.error(
2073
+ `Unexpected error retrieving profile for ${params.accountId}:`,
2074
+ error
2075
+ );
2076
+ this.executeResult = {
2077
+ success: false,
2078
+ error: `Unexpected error retrieving profile for ${params.accountId}: ${
2079
+ error instanceof Error ? error.message : String(error)
2080
+ }`,
2081
+ } as ExecuteResult & { rawResult?: unknown };
2082
+ }
2083
+
2084
+ return this;
2085
+ }
2086
+
2087
+ /**
2088
+ * Override execute to return stored HCS10 operation results
2089
+ */
2090
+ public override async execute(): Promise<ExecuteResult> {
2091
+ if (this.executeResult) {
2092
+ return {
2093
+ success: this.executeResult.success,
2094
+ transactionId: this.executeResult.transactionId,
2095
+ receipt: this.executeResult.receipt,
2096
+ scheduleId: this.executeResult.scheduleId,
2097
+ error: this.executeResult.error,
2098
+ rawResult: this.executeResult.rawResult,
2099
+ notes: this.notes,
2100
+ } as ExecuteResult & { rawResult?: unknown; notes?: string[] };
2101
+ }
2102
+
2103
+ return {
2104
+ success: false,
2105
+ error: 'No operation result available. Call a builder method first.',
2106
+ };
2107
+ }
2108
+ }