@hashgraphonline/conversational-agent 0.1.214 → 0.1.217

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 (170) hide show
  1. package/cli/dist/CLIApp.d.ts +9 -0
  2. package/cli/dist/CLIApp.js +127 -0
  3. package/cli/dist/LocalConversationalAgent.d.ts +37 -0
  4. package/cli/dist/LocalConversationalAgent.js +58 -0
  5. package/cli/dist/app.d.ts +16 -0
  6. package/cli/dist/app.js +13 -0
  7. package/cli/dist/cli.d.ts +2 -0
  8. package/cli/dist/cli.js +51 -0
  9. package/cli/dist/components/AppContainer.d.ts +16 -0
  10. package/cli/dist/components/AppContainer.js +24 -0
  11. package/cli/dist/components/AppScreens.d.ts +2 -0
  12. package/cli/dist/components/AppScreens.js +259 -0
  13. package/cli/dist/components/ChatScreen.d.ts +15 -0
  14. package/cli/dist/components/ChatScreen.js +39 -0
  15. package/cli/dist/components/DebugLoadingScreen.d.ts +5 -0
  16. package/cli/dist/components/DebugLoadingScreen.js +31 -0
  17. package/cli/dist/components/LoadingScreen.d.ts +2 -0
  18. package/cli/dist/components/LoadingScreen.js +16 -0
  19. package/cli/dist/components/LoadingScreenDebug.d.ts +5 -0
  20. package/cli/dist/components/LoadingScreenDebug.js +27 -0
  21. package/cli/dist/components/MCPConfigScreen.d.ts +28 -0
  22. package/cli/dist/components/MCPConfigScreen.js +168 -0
  23. package/cli/dist/components/ScreenRouter.d.ts +12 -0
  24. package/cli/dist/components/ScreenRouter.js +22 -0
  25. package/cli/dist/components/SetupScreen.d.ts +15 -0
  26. package/cli/dist/components/SetupScreen.js +65 -0
  27. package/cli/dist/components/SingleLoadingScreen.d.ts +5 -0
  28. package/cli/dist/components/SingleLoadingScreen.js +27 -0
  29. package/cli/dist/components/StatusBadge.d.ts +7 -0
  30. package/cli/dist/components/StatusBadge.js +28 -0
  31. package/cli/dist/components/TerminalWindow.d.ts +8 -0
  32. package/cli/dist/components/TerminalWindow.js +24 -0
  33. package/cli/dist/components/WelcomeScreen.d.ts +11 -0
  34. package/cli/dist/components/WelcomeScreen.js +47 -0
  35. package/cli/dist/context/AppContext.d.ts +68 -0
  36. package/cli/dist/context/AppContext.js +363 -0
  37. package/cli/dist/hooks/useInitializeAgent.d.ts +19 -0
  38. package/cli/dist/hooks/useInitializeAgent.js +28 -0
  39. package/cli/dist/hooks/useStableState.d.ts +38 -0
  40. package/cli/dist/hooks/useStableState.js +68 -0
  41. package/cli/dist/managers/AgentManager.d.ts +57 -0
  42. package/cli/dist/managers/AgentManager.js +119 -0
  43. package/cli/dist/managers/ConfigManager.d.ts +53 -0
  44. package/cli/dist/managers/ConfigManager.js +173 -0
  45. package/cli/dist/types.d.ts +31 -0
  46. package/cli/dist/types.js +19 -0
  47. package/dist/cjs/base-agent.d.ts +2 -0
  48. package/dist/cjs/conversational-agent.d.ts +8 -0
  49. package/dist/cjs/core/ToolRegistry.d.ts +130 -0
  50. package/dist/cjs/execution/ExecutionPipeline.d.ts +81 -0
  51. package/dist/cjs/forms/FormEngine.d.ts +121 -0
  52. package/dist/cjs/forms/field-type-registry.d.ts +51 -0
  53. package/dist/cjs/forms/form-generator.d.ts +123 -0
  54. package/dist/cjs/forms/index.d.ts +2 -0
  55. package/dist/cjs/forms/types.d.ts +108 -0
  56. package/dist/cjs/index.cjs +1 -1
  57. package/dist/cjs/index.cjs.map +1 -1
  58. package/dist/cjs/index.d.ts +5 -0
  59. package/dist/cjs/langchain/FormAwareAgentExecutor.d.ts +108 -0
  60. package/dist/cjs/langchain/FormValidatingToolWrapper.d.ts +81 -0
  61. package/dist/cjs/langchain-agent.d.ts +65 -0
  62. package/dist/cjs/memory/ContentStorage.d.ts +7 -0
  63. package/dist/cjs/memory/SmartMemoryManager.d.ts +1 -0
  64. package/dist/cjs/services/ContentStoreManager.d.ts +11 -1
  65. package/dist/cjs/utils/ResponseFormatter.d.ts +26 -0
  66. package/dist/esm/index.js +8 -1
  67. package/dist/esm/index.js.map +1 -1
  68. package/dist/esm/index12.js +1 -1
  69. package/dist/esm/index12.js.map +1 -1
  70. package/dist/esm/index14.js +23 -5
  71. package/dist/esm/index14.js.map +1 -1
  72. package/dist/esm/index15.js +25 -4
  73. package/dist/esm/index15.js.map +1 -1
  74. package/dist/esm/index16.js +4 -2
  75. package/dist/esm/index16.js.map +1 -1
  76. package/dist/esm/index17.js +2 -7
  77. package/dist/esm/index17.js.map +1 -1
  78. package/dist/esm/index18.js +609 -36
  79. package/dist/esm/index18.js.map +1 -1
  80. package/dist/esm/index19.js +229 -84
  81. package/dist/esm/index19.js.map +1 -1
  82. package/dist/esm/index20.js +111 -17
  83. package/dist/esm/index20.js.map +1 -1
  84. package/dist/esm/index21.js +44 -7
  85. package/dist/esm/index21.js.map +1 -1
  86. package/dist/esm/index22.js +86 -157
  87. package/dist/esm/index22.js.map +1 -1
  88. package/dist/esm/index23.js +32 -150
  89. package/dist/esm/index23.js.map +1 -1
  90. package/dist/esm/index24.js +746 -80
  91. package/dist/esm/index24.js.map +1 -1
  92. package/dist/esm/index25.js +154 -45
  93. package/dist/esm/index25.js.map +1 -1
  94. package/dist/esm/index26.js +149 -24
  95. package/dist/esm/index26.js.map +1 -1
  96. package/dist/esm/index27.js +196 -217
  97. package/dist/esm/index27.js.map +1 -1
  98. package/dist/esm/index28.js +187 -0
  99. package/dist/esm/index28.js.map +1 -0
  100. package/dist/esm/index29.js +308 -0
  101. package/dist/esm/index29.js.map +1 -0
  102. package/dist/esm/index30.js +159 -0
  103. package/dist/esm/index30.js.map +1 -0
  104. package/dist/esm/index31.js +68 -0
  105. package/dist/esm/index31.js.map +1 -0
  106. package/dist/esm/index32.js +30 -0
  107. package/dist/esm/index32.js.map +1 -0
  108. package/dist/esm/index33.js +95 -0
  109. package/dist/esm/index33.js.map +1 -0
  110. package/dist/esm/index34.js +245 -0
  111. package/dist/esm/index34.js.map +1 -0
  112. package/dist/esm/index5.js +2 -2
  113. package/dist/esm/index5.js.map +1 -1
  114. package/dist/esm/index6.js +68 -25
  115. package/dist/esm/index6.js.map +1 -1
  116. package/dist/esm/index7.js.map +1 -1
  117. package/dist/esm/index8.js +744 -70
  118. package/dist/esm/index8.js.map +1 -1
  119. package/dist/types/base-agent.d.ts +2 -0
  120. package/dist/types/conversational-agent.d.ts +8 -0
  121. package/dist/types/core/ToolRegistry.d.ts +130 -0
  122. package/dist/types/execution/ExecutionPipeline.d.ts +81 -0
  123. package/dist/types/forms/FormEngine.d.ts +121 -0
  124. package/dist/types/forms/field-type-registry.d.ts +51 -0
  125. package/dist/types/forms/form-generator.d.ts +123 -0
  126. package/dist/types/forms/index.d.ts +2 -0
  127. package/dist/types/forms/types.d.ts +108 -0
  128. package/dist/types/index.d.ts +5 -0
  129. package/dist/types/langchain/FormAwareAgentExecutor.d.ts +108 -0
  130. package/dist/types/langchain/FormValidatingToolWrapper.d.ts +81 -0
  131. package/dist/types/langchain-agent.d.ts +65 -0
  132. package/dist/types/memory/ContentStorage.d.ts +7 -0
  133. package/dist/types/memory/SmartMemoryManager.d.ts +1 -0
  134. package/dist/types/services/ContentStoreManager.d.ts +11 -1
  135. package/dist/types/utils/ResponseFormatter.d.ts +26 -0
  136. package/package.json +35 -34
  137. package/src/base-agent.ts +2 -0
  138. package/src/config/system-message.ts +14 -0
  139. package/src/context/ReferenceContextManager.ts +1 -1
  140. package/src/conversational-agent.ts +95 -38
  141. package/src/core/ToolRegistry.ts +358 -0
  142. package/src/execution/ExecutionPipeline.ts +301 -0
  143. package/src/forms/FormEngine.ts +443 -0
  144. package/src/forms/field-type-registry.ts +203 -0
  145. package/src/forms/form-generator.ts +841 -0
  146. package/src/forms/index.ts +2 -0
  147. package/src/forms/types.ts +125 -0
  148. package/src/index.ts +9 -0
  149. package/src/langchain/FormAwareAgentExecutor.ts +971 -0
  150. package/src/langchain/FormValidatingToolWrapper.ts +355 -0
  151. package/src/langchain-agent.ts +1034 -87
  152. package/src/mcp/ContentProcessor.ts +20 -4
  153. package/src/mcp/MCPClientManager.ts +1 -1
  154. package/src/mcp/adapters/langchain.ts +1 -1
  155. package/src/memory/ContentStorage.ts +25 -5
  156. package/src/memory/SmartMemoryManager.ts +27 -4
  157. package/src/memory/TokenCounter.ts +1 -1
  158. package/src/plugins/hbar/HbarPlugin.ts +0 -1
  159. package/src/scripts/test-external-tool-wrapper.ts +103 -0
  160. package/src/scripts/test-hedera-kit-wrapper.ts +265 -0
  161. package/src/scripts/test-inscribe-form-generation.ts +494 -0
  162. package/src/scripts/test-inscribe-wrapper-verification.ts +220 -0
  163. package/src/services/ContentStoreManager.ts +23 -9
  164. package/src/services/EntityResolver.ts +2 -9
  165. package/src/tools/EntityResolverTool.ts +5 -8
  166. package/src/utils/ResponseFormatter.ts +146 -0
  167. package/cli/readme.md +0 -181
  168. package/dist/cjs/langchain/ContentAwareAgentExecutor.d.ts +0 -14
  169. package/dist/types/langchain/ContentAwareAgentExecutor.d.ts +0 -14
  170. package/src/langchain/ContentAwareAgentExecutor.ts +0 -19
@@ -1 +1 @@
1
- {"version":3,"file":"index18.js","sources":["../../src/plugins/hbar/TransferHbarTool.ts"],"sourcesContent":["import { z } from 'zod';\nimport { HbarTransferParams } from './types';\nimport { AccountBuilder } from './AccountBuilder';\nimport { BaseHederaTransactionTool, BaseServiceBuilder } from 'hedera-agent-kit';\n\nconst HbarTransferInputSchema = z.object({\n accountId: z\n .string()\n .describe('Account ID for the transfer (e.g., \"0.0.xxxx\").'),\n amount: z\n .union([z.number(), z.string()])\n .describe(\n 'HBAR amount in decimal format (e.g., 1 for 1 HBAR, 0.5 for 0.5 HBAR). Positive for credit, negative for debit. DO NOT multiply by 10^8 for tinybars - just use the HBAR amount directly.'\n ),\n});\n\nconst TransferHbarZodSchemaCore = z.object({\n transfers: z\n .array(HbarTransferInputSchema)\n .min(1)\n .describe(\n 'Array of transfers. For simple transfers from your operator account, just include the recipient with positive amount: [{accountId: \"0.0.800\", amount: 1}]. For complex multi-party transfers, include all parties with negative amounts for senders and positive for receivers.'\n ),\n memo: z.string().optional().describe('Optional. Memo for the transaction.'),\n});\n\n/**\n * A Hedera transaction tool for transferring HBAR between accounts.\n * Supports single and multi-party transfers with automatic balance validation.\n * Extends BaseHederaTransactionTool to handle HBAR transfer transactions on the Hedera Hashgraph.\n */\nexport class TransferHbarTool extends BaseHederaTransactionTool<\n typeof TransferHbarZodSchemaCore\n> {\n name = 'hedera-account-transfer-hbar-v2';\n description =\n 'PRIMARY TOOL FOR HBAR TRANSFERS: Transfers HBAR between accounts. For simple transfers from the operator account, just specify the recipient with a positive amount (e.g., [{accountId: \"0.0.800\", amount: 1}] to send 1 HBAR to 0.0.800). The sender will be automatically added. For multi-party transfers (e.g., \"A sends 5 HBAR to C and B sends 3 HBAR to C\"), include ALL transfers with their amounts (negative for senders, positive for receivers).';\n specificInputSchema = TransferHbarZodSchemaCore;\n namespace = 'account';\n\n\n /**\n * Creates and returns the service builder for account operations.\n * \n * @returns BaseServiceBuilder instance configured for account operations\n */\n protected getServiceBuilder(): BaseServiceBuilder {\n return new AccountBuilder(this.hederaKit) as BaseServiceBuilder;\n }\n\n /**\n * Executes the HBAR transfer using the provided builder and arguments.\n * Validates that all transfers sum to zero before execution.\n * \n * @param builder - The service builder instance for executing transactions\n * @param specificArgs - The validated transfer parameters including transfers array and optional memo\n * @returns Promise that resolves when the transfer is complete\n */\n protected async callBuilderMethod(\n builder: BaseServiceBuilder,\n specificArgs: z.infer<typeof TransferHbarZodSchemaCore>\n ): Promise<void> {\n await (builder as AccountBuilder).transferHbar(\n specificArgs as unknown as HbarTransferParams\n );\n }\n}"],"names":[],"mappings":";;;AAKA,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,WAAW,EACR,SACA,SAAS,iDAAiD;AAAA,EAC7D,QAAQ,EACL,MAAM,CAAC,EAAE,OAAA,GAAU,EAAE,QAAQ,CAAC,EAC9B;AAAA,IACC;AAAA,EAAA;AAEN,CAAC;AAED,MAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,WAAW,EACR,MAAM,uBAAuB,EAC7B,IAAI,CAAC,EACL;AAAA,IACC;AAAA,EAAA;AAAA,EAEJ,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,SAAS,qCAAqC;AAC5E,CAAC;AAOM,MAAM,yBAAyB,0BAEpC;AAAA,EAFK,cAAA;AAAA,UAAA,GAAA,SAAA;AAGL,SAAA,OAAO;AACP,SAAA,cACE;AACF,SAAA,sBAAsB;AACtB,SAAA,YAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,oBAAwC;AAChD,WAAO,IAAI,eAAe,KAAK,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAgB,kBACd,SACA,cACe;AACf,UAAO,QAA2B;AAAA,MAChC;AAAA,IAAA;AAAA,EAEJ;AACF;"}
1
+ {"version":3,"file":"index18.js","sources":["../../src/forms/form-generator.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport type {\n FormConfig,\n FormField,\n ValidationError,\n FormMessage,\n FormFieldType,\n} from './types';\nimport {\n extractRenderConfigs,\n generateFieldOrdering,\n type RenderConfigSchema,\n type ZodSchemaWithRender,\n type ExtractedRenderConfig,\n} from '@hashgraphonline/standards-agent-kit';\nimport { Logger } from '@hashgraphonline/standards-sdk';\nimport { fieldTypeRegistry } from './field-type-registry';\n\ntype FieldPriority = 'essential' | 'common' | 'advanced' | 'expert';\n\n/**\n * Generates forms from Zod validation failures\n */\nexport class FormGenerator {\n private logger: Logger;\n\n constructor() {\n this.logger = new Logger({ module: 'FormGenerator' });\n }\n\n /**\n * Creates a form message from a Zod validation error\n * @param error The Zod validation error\n * @param schema The original Zod schema\n * @param toolName Name of the tool that failed validation\n * @param originalPrompt The user's original request\n * @returns FormMessage to send to the chat UI\n */\n generateFormFromError(\n error: ZodError,\n schema: z.ZodSchema,\n toolName: string,\n originalPrompt: string\n ): FormMessage {\n const validationErrors = this.extractValidationErrors(error);\n const missingFields = this.identifyMissingFields(validationErrors, schema);\n const formConfig = this.createFormConfig(schema, missingFields, toolName);\n\n return {\n type: 'form',\n id: `form_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n formConfig,\n originalPrompt,\n toolName,\n validationErrors,\n };\n }\n\n /**\n * Generates a form from a schema and partial input\n * @param schema The Zod schema to generate a form from\n * @param partialInput Any partial input already provided\n * @param context Additional context about the tool\n * @param preCalculatedMissingFields Optional pre-calculated missing fields set. If undefined, includes all fields from schema.\n * @returns FormMessage to send to the chat UI\n */\n async generateFormFromSchema(\n schema: z.ZodSchema,\n partialInput: unknown,\n context: { toolName: string; toolDescription?: string },\n preCalculatedMissingFields?: Set<string>\n ): Promise<FormMessage> {\n let missingFields: Set<string>;\n\n this.logger.info(`šŸ FormGenerator.generateFormFromSchema starting`, {\n toolName: context.toolName,\n partialInput,\n hasSchema: !!schema,\n hasShape: !!(schema && (schema as any).shape),\n hasPreCalculatedFields: preCalculatedMissingFields !== undefined,\n preCalculatedFieldsSize: preCalculatedMissingFields?.size || 0,\n });\n\n if (preCalculatedMissingFields !== undefined) {\n missingFields = preCalculatedMissingFields;\n this.logger.info(`šŸ“‹ Using pre-calculated missing fields`, {\n missingFieldsCount: missingFields.size,\n missingFields: Array.from(missingFields),\n });\n } else {\n missingFields = new Set<string>();\n\n const zodObject = this.extractZodObject(schema);\n if (zodObject) {\n const shape = zodObject.shape;\n for (const fieldName of Object.keys(shape)) {\n missingFields.add(fieldName);\n this.logger.info(\n `⭐ Including all fields from focused schema: ${fieldName}`\n );\n }\n }\n\n this.logger.info(`šŸ“‹ Using ALL fields from focused schema`, {\n totalFields: zodObject ? Object.keys(zodObject.shape).length : 0,\n missingFieldsCount: missingFields.size,\n missingFields: Array.from(missingFields),\n });\n }\n\n const formConfig = this.createFormConfig(\n schema,\n missingFields,\n context.toolName,\n preCalculatedMissingFields\n );\n\n return {\n type: 'form',\n id: `form_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n formConfig,\n originalPrompt: context.toolDescription || `Complete ${context.toolName}`,\n toolName: context.toolName,\n validationErrors: [],\n };\n }\n\n /**\n * Extracts validation errors from ZodError\n */\n private extractValidationErrors(error: ZodError): ValidationError[] {\n return error.issues.map((issue) => ({\n path: issue.path.map((p) => String(p)),\n message: issue.message,\n code: issue.code,\n }));\n }\n\n /**\n * Identifies which fields are missing or invalid from validation errors\n */\n private identifyMissingFields(\n errors: ValidationError[],\n _schema: z.ZodSchema\n ): Set<string> {\n const missingFields = new Set<string>();\n\n errors.forEach((error) => {\n const fieldPath = error.path.join('.');\n if (fieldPath) {\n missingFields.add(fieldPath);\n }\n });\n\n return missingFields;\n }\n\n /**\n * Creates form configuration from schema\n */\n private createFormConfig(\n schema: z.ZodSchema,\n missingFields: Set<string>,\n toolName: string,\n preCalculatedMissingFields?: Set<string>\n ): FormConfig {\n const extractedConfig = this.extractRenderConfigsSafely(schema);\n const fieldOrdering = this.generateFieldOrderingSafely(schema);\n const fields = this.generateFormFields(\n schema,\n extractedConfig,\n missingFields,\n fieldOrdering,\n preCalculatedMissingFields\n );\n\n return {\n title: this.generateFormTitle(toolName),\n description: this.generateFormDescription(toolName, missingFields.size),\n fields,\n submitLabel: 'Continue',\n cancelLabel: 'Cancel',\n metadata: {\n toolName,\n missingFieldCount: missingFields.size,\n },\n };\n }\n\n /**\n * Safely extracts render configs from schema\n */\n private extractRenderConfigsSafely(\n schema: z.ZodSchema\n ): ExtractedRenderConfig {\n try {\n if (typeof extractRenderConfigs === 'function') {\n return extractRenderConfigs(schema as unknown as ZodSchemaWithRender);\n }\n } catch (error) {\n this.logger.warn('Could not extract render configs:', error);\n }\n return {\n fields: {},\n groups: {},\n order: [],\n metadata: {},\n };\n }\n\n /**\n * Safely generates field ordering from schema\n */\n private generateFieldOrderingSafely(schema: z.ZodSchema): {\n sections: Array<{ fields: string[] }>;\n } {\n try {\n if (typeof generateFieldOrdering === 'function') {\n const ordering = generateFieldOrdering(\n schema as unknown as ZodSchemaWithRender\n );\n\n const sections = Object.values(ordering.sections).map((section) => ({\n fields: section.fields,\n }));\n return { sections };\n }\n } catch (error) {\n this.logger.warn('Could not generate field ordering:', error);\n }\n return { sections: [] };\n }\n\n /**\n * Determines field priority for progressive disclosure\n */\n private getFieldPriority(\n name: string,\n renderConfig?: RenderConfigSchema,\n isRequired?: boolean\n ): FieldPriority {\n if (renderConfig?.ui?.priority) {\n const priority = renderConfig.ui.priority as string;\n if (['essential', 'common', 'advanced', 'expert'].includes(priority)) {\n return priority as FieldPriority;\n }\n }\n\n if (isRequired === true) {\n return 'essential';\n }\n\n const ui = renderConfig?.ui as Record<string, unknown> | undefined;\n if (ui?.advanced === true) {\n return 'advanced';\n }\n\n if (ui?.expert === true) {\n return 'expert';\n }\n\n return 'common';\n }\n\n /**\n * Determines which fields should be included in the form\n */\n private determineFieldsToInclude(\n schema: z.ZodSchema,\n missingFields: Set<string>,\n preCalculatedMissingFields?: Set<string>\n ): Set<string> {\n const fieldsToInclude = new Set<string>();\n\n if (preCalculatedMissingFields === undefined) {\n this.logger.info(\n `⭐ Focused schema mode - including ALL fields from schema`\n );\n const allSchemaFields = this.extractFieldsFromSchema(schema);\n allSchemaFields.forEach((fieldName) => {\n fieldsToInclude.add(fieldName);\n this.logger.info(`āœ… Including focused schema field: ${fieldName}`);\n });\n } else if (preCalculatedMissingFields.size > 0) {\n this.logger.info(\n `šŸ“‹ Using ONLY pre-calculated missing fields (${preCalculatedMissingFields.size} fields)`,\n { fields: Array.from(preCalculatedMissingFields) }\n );\n preCalculatedMissingFields.forEach((fieldName) => {\n fieldsToInclude.add(fieldName);\n this.logger.info(`āœ… Including pre-calculated field: ${fieldName}`);\n });\n } else {\n this.logger.info(\n 'āš ļø No pre-calculated fields, falling back to schema analysis'\n );\n this.includeRequiredMissingFields(schema, missingFields, fieldsToInclude);\n }\n\n return fieldsToInclude;\n }\n\n /**\n * Includes required fields that are missing\n */\n private includeRequiredMissingFields(\n schema: z.ZodSchema,\n missingFields: Set<string>,\n fieldsToInclude: Set<string>\n ): void {\n const allSchemaFields = this.extractFieldsFromSchema(schema);\n allSchemaFields.forEach((fieldName) => {\n const isRequired = this.isFieldRequired(schema, fieldName);\n const isMissing = missingFields.has(fieldName);\n const shouldInclude = isMissing && isRequired;\n\n this.logger.info(`šŸ” FormGenerator field inclusion check: ${fieldName}`, {\n isRequired,\n isMissing,\n shouldInclude,\n });\n\n if (shouldInclude) {\n fieldsToInclude.add(fieldName);\n }\n });\n }\n\n /**\n * Creates form fields from ordered field names\n */\n private createOrderedFields(\n fieldsToInclude: Set<string>,\n fieldOrdering: { sections: Array<{ fields: string[] }> },\n extractedConfig: ExtractedRenderConfig,\n schema: z.ZodSchema\n ): FormField[] {\n const fields: FormField[] = [];\n const processedFields = new Set<string>();\n\n if (fieldOrdering.sections.length > 0) {\n const orderedFieldNames = fieldOrdering.sections.flatMap((s) => s.fields);\n orderedFieldNames.forEach((fieldName) => {\n if (fieldsToInclude.has(fieldName) && !processedFields.has(fieldName)) {\n const field = this.createFormField(\n fieldName,\n extractedConfig.fields[fieldName],\n schema,\n fieldName\n );\n if (field) {\n fields.push(field);\n processedFields.add(fieldName);\n }\n }\n });\n }\n\n fieldsToInclude.forEach((fieldName) => {\n if (!processedFields.has(fieldName)) {\n const field = this.createFormField(\n fieldName,\n extractedConfig.fields[fieldName],\n schema,\n fieldName\n );\n if (field) {\n fields.push(field);\n }\n }\n });\n\n return fields;\n }\n\n /**\n * Generates form fields from schema and validation errors\n */\n private generateFormFields(\n schema: z.ZodSchema,\n extractedConfig: ExtractedRenderConfig,\n missingFields: Set<string>,\n fieldOrdering: { sections: Array<{ fields: string[] }> },\n preCalculatedMissingFields?: Set<string>\n ): FormField[] {\n const fieldsToInclude = this.determineFieldsToInclude(\n schema,\n missingFields,\n preCalculatedMissingFields\n );\n\n let fields = this.createOrderedFields(\n fieldsToInclude,\n fieldOrdering,\n extractedConfig,\n schema\n );\n\n if (fields.length === 0 && missingFields.size > 0) {\n fields = Array.from(missingFields)\n .map((fieldName) =>\n this.createFormField(\n fieldName,\n extractedConfig.fields[fieldName],\n schema,\n fieldName\n )\n )\n .filter(\n (field): field is FormField => field !== null && field !== undefined\n );\n }\n\n return fields;\n }\n\n /**\n * Creates a single form field\n */\n private createFormField(\n fieldName: string,\n renderConfig?: RenderConfigSchema,\n schema?: z.ZodSchema,\n fieldPath?: string\n ): FormField {\n const type = this.mapFieldType(renderConfig?.fieldType, schema, fieldPath);\n const isRequired = this.isFieldRequired(schema, fieldPath || fieldName);\n\n const field: FormField = {\n name: fieldName,\n label: renderConfig?.ui?.label || this.humanizeFieldName(fieldName),\n type,\n required: isRequired,\n priority: this.getFieldPriority(fieldName, renderConfig, isRequired),\n };\n\n if (renderConfig) {\n field.renderConfig = renderConfig;\n }\n\n if (renderConfig?.ui?.placeholder) {\n field.placeholder = renderConfig.ui.placeholder;\n }\n\n if (renderConfig?.ui?.helpText) {\n field.helpText = renderConfig.ui.helpText;\n }\n\n if (renderConfig?.constraints) {\n const validation: Record<string, unknown> = {};\n if (renderConfig.constraints.min !== undefined)\n validation.min = renderConfig.constraints.min;\n if (renderConfig.constraints.max !== undefined)\n validation.max = renderConfig.constraints.max;\n if (renderConfig.constraints.minLength !== undefined)\n validation.minLength = renderConfig.constraints.minLength;\n if (renderConfig.constraints.maxLength !== undefined)\n validation.maxLength = renderConfig.constraints.maxLength;\n if (renderConfig.constraints.pattern !== undefined)\n validation.pattern = renderConfig.constraints.pattern;\n\n if (Object.keys(validation).length > 0) {\n field.validation = validation;\n }\n }\n\n if (renderConfig?.options) {\n field.options = renderConfig.options.map((opt) => ({\n value: String(opt.value),\n label: opt.label,\n ...(opt.disabled !== undefined && { disabled: opt.disabled }),\n }));\n }\n\n return field;\n }\n\n /**\n * Maps render config field type to form field type with fallback inference\n */\n private mapFieldType(\n fieldType?: string,\n schema?: z.ZodSchema,\n fieldPath?: string\n ): FormFieldType {\n if (!fieldType && schema && fieldPath) {\n const inferredType = this.inferTypeFromSchema(schema, fieldPath);\n if (inferredType) {\n return inferredType;\n }\n }\n\n if (!fieldType && fieldPath) {\n const registryType = fieldTypeRegistry.detectType(fieldPath);\n if (registryType) {\n return registryType;\n }\n }\n\n if (!fieldType) {\n return 'text';\n }\n\n const normalizedType = fieldType.toLowerCase();\n\n if (['text', 'string'].includes(normalizedType)) return 'text';\n if (['number', 'integer', 'float', 'decimal'].includes(normalizedType))\n return 'number';\n if (['select', 'enum', 'dropdown'].includes(normalizedType))\n return 'select';\n if (['checkbox', 'boolean', 'bool'].includes(normalizedType))\n return 'checkbox';\n if (['textarea', 'longtext', 'multiline'].includes(normalizedType))\n return 'textarea';\n if (['file', 'upload', 'attachment'].includes(normalizedType))\n return 'file';\n if (['array', 'list'].includes(normalizedType)) return 'array';\n if (['object', 'json'].includes(normalizedType)) return 'object';\n if (['currency', 'money', 'price'].includes(normalizedType))\n return 'currency';\n if (['percentage', 'percent'].includes(normalizedType)) return 'percentage';\n\n return 'text';\n }\n\n /**\n * Converts field name to human-readable label\n */\n private humanizeFieldName(fieldName: string): string {\n return fieldName\n .replace(/([A-Z])/g, ' $1')\n .replace(/_/g, ' ')\n .replace(/\\./g, ' ')\n .trim()\n .split(' ')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n }\n\n /**\n * Generates a title for the form\n */\n private generateFormTitle(toolName: string): string {\n const cleanName = toolName\n .replace(/Tool$/, '')\n .replace(/Hedera/g, '')\n .replace(/([A-Z])/g, ' $1')\n .trim();\n\n return `Complete ${cleanName} Information`;\n }\n\n /**\n * Safely extracts ZodObject from a schema, returns null if not an object schema\n */\n private extractZodObject(\n schema: z.ZodSchema\n ): z.ZodObject<z.ZodRawShape> | null {\n try {\n const def = (schema as z.ZodType)._def as { typeName?: string };\n if (def && def.typeName === 'ZodObject') {\n return schema as z.ZodObject<z.ZodRawShape>;\n }\n } catch (error) {\n this.logger.debug('Could not extract ZodObject from schema:', error);\n }\n return null;\n }\n\n /**\n * Extracts field names from Zod schema structure\n */\n private extractFieldsFromSchema(schema: z.ZodSchema): string[] {\n const fields: string[] = [];\n\n const zodObject = this.extractZodObject(schema);\n if (zodObject) {\n fields.push(...Object.keys(zodObject.shape));\n return fields;\n }\n\n try {\n const def = (schema as z.ZodType)._def as {\n typeName?: string;\n options?: z.ZodType[];\n };\n if (def && def.typeName === 'ZodUnion' && def.options) {\n const firstOption = def.options[0];\n const firstOptionObject = this.extractZodObject(firstOption);\n if (firstOptionObject) {\n fields.push(...Object.keys(firstOptionObject.shape));\n }\n }\n } catch (error) {\n this.logger.debug(\n 'Could not extract fields from schema structure:',\n error\n );\n }\n\n return fields;\n }\n\n /**\n * Infers field type from Zod schema\n */\n private inferTypeFromSchema(\n schema: z.ZodSchema,\n fieldPath: string\n ): FormFieldType | null {\n try {\n const zodObject = this.extractZodObject(schema);\n if (!zodObject) return null;\n\n const shape = zodObject.shape;\n if (!shape) return null;\n\n let fieldSchema = shape[fieldPath] as z.ZodType | undefined;\n if (!fieldSchema) return null;\n\n const fieldDef = fieldSchema._def as {\n typeName?: string;\n innerType?: z.ZodType;\n };\n if (\n fieldDef &&\n fieldDef.typeName === 'ZodOptional' &&\n fieldDef.innerType\n ) {\n fieldSchema = fieldDef.innerType;\n }\n\n if (!fieldSchema || !fieldSchema._def) return null;\n\n const typeDef = fieldSchema._def as { typeName?: string };\n const fieldTypeName = typeDef.typeName;\n const lowerPath = fieldPath.toLowerCase();\n\n switch (fieldTypeName) {\n case 'ZodString':\n if (lowerPath.includes('memo') || lowerPath.includes('description')) {\n return 'textarea';\n }\n return 'text';\n case 'ZodNumber':\n if (lowerPath.includes('percent')) {\n return 'percentage';\n }\n if (lowerPath.includes('price') || lowerPath.includes('cost')) {\n return 'currency';\n }\n return 'number';\n case 'ZodBoolean':\n return 'checkbox';\n case 'ZodEnum':\n case 'ZodNativeEnum':\n return 'select';\n case 'ZodArray':\n return 'array';\n case 'ZodObject':\n return 'object';\n default:\n return 'text';\n }\n } catch (error) {\n this.logger.debug('Could not infer type from schema:', error);\n }\n return null;\n }\n\n /**\n * Determines if a field is required based on the Zod schema\n */\n private isFieldRequired(schema?: z.ZodSchema, fieldPath?: string): boolean {\n if (!schema || !fieldPath) {\n return false;\n }\n\n try {\n const zodObject = this.extractZodObject(schema);\n if (!zodObject) return false;\n\n const shape = zodObject.shape;\n if (!shape || !shape[fieldPath]) return false;\n\n const fieldSchema = shape[fieldPath] as z.ZodType;\n if (!fieldSchema || !fieldSchema._def) return true;\n\n const fieldDef = fieldSchema._def as {\n typeName?: string;\n defaultValue?: unknown;\n };\n const typeName = fieldDef.typeName;\n\n if (typeName === 'ZodOptional') {\n return false;\n }\n\n if (typeName === 'ZodDefault') {\n return false;\n }\n\n if (fieldDef.defaultValue !== undefined) {\n return false;\n }\n\n return true;\n } catch (error) {\n this.logger.debug(\n `Could not determine if field ${fieldPath} is required:`,\n error\n );\n }\n\n return false;\n }\n\n /**\n * Generates a description for the form\n */\n private generateFormDescription(\n toolName: string,\n fieldCount: number\n ): string {\n if (fieldCount === 0) {\n return 'Please provide the required information to continue with your request.';\n }\n\n return `Please provide the following ${fieldCount} required field${\n fieldCount !== 1 ? 's' : ''\n } to continue with your request.`;\n }\n\n /**\n * Generates JSON Schema and uiSchema from a Zod schema for use with @rjsf/core\n * @param zodSchema The Zod schema to convert\n * @param partialInput Existing input data to filter out fields that already have values\n * @param missingFields Set of fields that are missing and should be shown\n * @returns Object containing jsonSchema and uiSchema\n */\n public generateJsonSchemaForm(\n zodSchema: z.ZodObject<z.ZodRawShape>,\n partialInput?: Record<string, unknown>,\n missingFields?: Set<string>\n ) {\n const fullJsonSchema = zodToJsonSchema(zodSchema, {\n target: 'jsonSchema7',\n });\n\n const uiSchema: Record<string, Record<string, unknown>> = {};\n\n let jsonSchema = fullJsonSchema;\n if (missingFields && missingFields.size > 0) {\n const fullSchemaAsObject = fullJsonSchema as {\n properties?: Record<string, unknown>;\n required?: string[];\n [key: string]: unknown;\n };\n if (\n fullSchemaAsObject.properties &&\n typeof fullSchemaAsObject.properties === 'object'\n ) {\n const filteredSchema = {\n ...fullSchemaAsObject,\n type: 'object' as const,\n properties: {} as Record<string, unknown>,\n required: [] as string[],\n };\n\n let fieldsAdded = 0;\n missingFields.forEach((fieldName) => {\n if (\n fullSchemaAsObject.properties &&\n fullSchemaAsObject.properties[fieldName]\n ) {\n filteredSchema.properties[fieldName] =\n fullSchemaAsObject.properties[fieldName];\n fieldsAdded++;\n }\n });\n\n if (Array.isArray(fullSchemaAsObject.required)) {\n filteredSchema.required = fullSchemaAsObject.required.filter(\n (field: string) => missingFields.has(field)\n );\n }\n\n if (fieldsAdded > 0) {\n jsonSchema = filteredSchema;\n }\n }\n }\n\n const fieldNames = this.extractFieldsFromSchema(zodSchema);\n\n fieldNames.forEach((fieldName) => {\n const isRequired = this.isFieldRequired(zodSchema, fieldName);\n const priority = this.getFieldPriority(fieldName, undefined, isRequired);\n const lower = fieldName.toLowerCase();\n\n if (\n lower === 'attributes' ||\n lower === 'metadata' ||\n lower === 'properties'\n ) {\n uiSchema[fieldName] = {\n 'ui:options': {\n collapsible: true,\n collapsed: true,\n },\n };\n }\n\n switch (priority) {\n case 'essential':\n if (isRequired) {\n uiSchema[fieldName] = {\n ...uiSchema[fieldName],\n 'ui:help': 'Required field',\n };\n }\n break;\n case 'advanced':\n case 'expert':\n uiSchema[fieldName] = {\n ...uiSchema[fieldName],\n 'ui:options': {\n ...(uiSchema[fieldName]?.['ui:options'] as\n | Record<string, unknown>\n | undefined),\n collapsed: true,\n },\n };\n break;\n }\n });\n\n return { jsonSchema, uiSchema };\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,106 +1,251 @@
1
1
  import { StructuredTool } from "@langchain/core/tools";
2
2
  import { z } from "zod";
3
3
  import { Logger } from "@hashgraphonline/standards-sdk";
4
- class AirdropToolWrapper extends StructuredTool {
5
- constructor(originalTool, agentKit) {
4
+ import { isFormValidatable } from "@hashgraphonline/standards-agent-kit";
5
+ class FormValidatingToolWrapper extends StructuredTool {
6
+ constructor(originalTool, formGenerator, config = {}) {
6
7
  super();
7
- this.name = "hedera-hts-airdrop-token";
8
- this.description = "Airdrops fungible tokens to multiple recipients. Automatically converts human-readable amounts to smallest units based on token decimals.";
9
- this.schema = z.object({
10
- tokenId: z.string().describe('The ID of the fungible token to airdrop (e.g., "0.0.yyyy").'),
11
- recipients: z.array(
12
- z.object({
13
- accountId: z.string().describe('Recipient account ID (e.g., "0.0.xxxx").'),
14
- amount: z.union([z.number(), z.string()]).describe(
15
- 'Amount in human-readable format (e.g., "10" for 10 tokens).'
16
- )
17
- })
18
- ).min(1).describe("Array of recipient objects, each with accountId and amount."),
19
- memo: z.string().optional().describe("Optional. Memo for the transaction.")
20
- });
21
8
  this.originalTool = originalTool;
22
- this.agentKit = agentKit;
23
- this.logger = new Logger({ module: "AirdropToolWrapper" });
9
+ this.formGenerator = formGenerator;
10
+ this.validationConfig = config;
11
+ this.logger = new Logger({ module: "FormValidatingToolWrapper" });
12
+ this.name = originalTool.name;
13
+ this.description = originalTool.description;
14
+ this.schema = originalTool.schema;
15
+ this.logger.info(`šŸ”§ FormValidatingToolWrapper created for tool: ${this.name}`, {
16
+ originalToolName: originalTool.name,
17
+ originalToolType: originalTool.constructor.name,
18
+ wrapperType: this.constructor.name
19
+ });
24
20
  }
25
- async _call(input) {
21
+ /**
22
+ * Validate the input against the schema
23
+ */
24
+ validateInput(input) {
26
25
  try {
27
- this.logger.info(
28
- `Processing airdrop request for token ${input.tokenId} with ${input.recipients.length} recipients`
29
- );
30
- const tokenInfo = await this.getTokenInfo(input.tokenId);
31
- const decimals = tokenInfo.decimals || 0;
32
- this.logger.info(`Token ${input.tokenId} has ${decimals} decimal places`);
33
- const convertedRecipients = input.recipients.map((recipient) => {
34
- const humanAmount = typeof recipient.amount === "string" ? parseFloat(recipient.amount) : recipient.amount;
35
- const smallestUnitAmount = this.convertToSmallestUnits(
36
- humanAmount,
37
- decimals
38
- );
39
- this.logger.info(
40
- `Converting amount for ${recipient.accountId}: ${humanAmount} tokens → ${smallestUnitAmount} smallest units`
26
+ this.schema.parse(input);
27
+ return { isValid: true };
28
+ } catch (error) {
29
+ if (error instanceof z.ZodError) {
30
+ const errors = error.errors.filter((err) => {
31
+ const fieldName = err.path[0];
32
+ return !this.validationConfig.skipFields?.includes(fieldName);
33
+ }).map((err) => `${err.path.join(".")}: ${err.message}`);
34
+ return { isValid: false, errors };
35
+ }
36
+ return { isValid: false, errors: ["Validation failed"] };
37
+ }
38
+ }
39
+ /**
40
+ * Gets the shape keys from the schema if it's a ZodObject
41
+ */
42
+ getSchemaShape() {
43
+ if (this.isZodObject(this.schema)) {
44
+ return Object.keys(this.schema.shape);
45
+ }
46
+ return [];
47
+ }
48
+ /**
49
+ * Executes the wrapped tool's original implementation directly, bypassing wrapper logic.
50
+ */
51
+ async executeOriginal(input, runManager) {
52
+ const tool = this.originalTool;
53
+ if ("_call" in tool && typeof tool._call === "function") {
54
+ return tool._call(input, runManager);
55
+ }
56
+ if ("call" in tool && typeof tool.call === "function") {
57
+ return tool.call(input, runManager);
58
+ }
59
+ throw new Error("Original tool has no callable implementation");
60
+ }
61
+ /**
62
+ * Provides access to the wrapped tool instance for executors that want to bypass the wrapper.
63
+ */
64
+ getOriginalTool() {
65
+ return this.originalTool;
66
+ }
67
+ /**
68
+ * Checks if tool implements FormValidatable method
69
+ */
70
+ hasFormValidatableMethod(tool, methodName) {
71
+ return tool !== null && typeof tool === "object" && methodName in tool && typeof tool[methodName] === "function";
72
+ }
73
+ /**
74
+ * Expose FormValidatable methods by delegating to the underlying tool when available.
75
+ */
76
+ getFormSchema() {
77
+ if (this.hasFormValidatableMethod(this.originalTool, "getFormSchema")) {
78
+ return this.originalTool.getFormSchema();
79
+ }
80
+ return this.schema;
81
+ }
82
+ getEssentialFields() {
83
+ if (this.hasFormValidatableMethod(this.originalTool, "getEssentialFields")) {
84
+ return this.originalTool.getEssentialFields();
85
+ }
86
+ return [];
87
+ }
88
+ isFieldEmpty(fieldName, value) {
89
+ if (this.hasFormValidatableMethod(this.originalTool, "isFieldEmpty")) {
90
+ return this.originalTool.isFieldEmpty(fieldName, value);
91
+ }
92
+ if (value === void 0 || value === null || value === "") {
93
+ return true;
94
+ }
95
+ if (Array.isArray(value) && value.length === 0) {
96
+ return true;
97
+ }
98
+ return false;
99
+ }
100
+ /**
101
+ * Calculates which fields are missing from the input
102
+ */
103
+ calculateMissingFields(input, isCustom) {
104
+ const missingFields = /* @__PURE__ */ new Set();
105
+ if (!isCustom) {
106
+ return missingFields;
107
+ }
108
+ const essentialFields = this.getEssentialFields();
109
+ for (const fieldName of essentialFields) {
110
+ const value = input[fieldName];
111
+ if (this.isFieldEmpty(fieldName, value)) {
112
+ missingFields.add(fieldName);
113
+ }
114
+ }
115
+ return missingFields;
116
+ }
117
+ /**
118
+ * Creates a form message with optional JSON schema
119
+ */
120
+ async createFormMessage(schema, input, missingFields) {
121
+ let formMessage = await this.formGenerator.generateFormFromSchema(
122
+ schema,
123
+ input,
124
+ {
125
+ toolName: this.name,
126
+ toolDescription: this.description
127
+ },
128
+ missingFields
129
+ );
130
+ if (this.isZodObject(schema)) {
131
+ try {
132
+ const { jsonSchema, uiSchema } = this.formGenerator.generateJsonSchemaForm(
133
+ schema,
134
+ input,
135
+ missingFields
41
136
  );
42
- return {
43
- ...recipient,
44
- amount: smallestUnitAmount.toString()
137
+ formMessage = {
138
+ ...formMessage,
139
+ jsonSchema,
140
+ uiSchema
45
141
  };
46
- });
47
- const convertedInput = {
48
- ...input,
49
- recipients: convertedRecipients
50
- };
51
- this.logger.info(`Calling original airdrop tool with converted amounts`);
52
- return await this.originalTool._call(convertedInput);
53
- } catch (error) {
54
- this.logger.error("Error in airdrop tool wrapper:", error);
55
- throw error;
142
+ } catch (error) {
143
+ this.logger.warn("Failed to generate JSON Schema for RJSF:", error);
144
+ }
56
145
  }
146
+ formMessage.partialInput = input;
147
+ return formMessage;
57
148
  }
58
- convertToSmallestUnits(amount, decimals) {
59
- return Math.floor(amount * Math.pow(10, decimals));
149
+ /**
150
+ * Type guard to check if a schema is a ZodObject
151
+ */
152
+ isZodObject(schema) {
153
+ const def = schema._def;
154
+ return !!(def && def.typeName === "ZodObject");
155
+ }
156
+ /**
157
+ * Check if we should generate a form for this tool invocation
158
+ */
159
+ shouldGenerateForm(input) {
160
+ this.logger.info(`shouldGenerateForm called for ${this.name}/${this.originalTool.name}`, {
161
+ input,
162
+ hasCustomValidation: !!this.validationConfig.customValidation
163
+ });
164
+ if (this.validationConfig.customValidation) {
165
+ const result = !this.validationConfig.customValidation(input);
166
+ this.logger.info(`Custom validation result: ${result}`);
167
+ return result;
168
+ }
169
+ if (isFormValidatable(this.originalTool)) {
170
+ this.logger.info(`Tool ${this.originalTool.name} implements FormValidatable, using custom logic`);
171
+ return this.originalTool.shouldGenerateForm(input);
172
+ }
173
+ this.logger.info(`Tool ${this.originalTool.name} using schema validation only`);
174
+ const validation = this.validateInput(input);
175
+ this.logger.info(`Schema validation for ${this.originalTool.name}:`, {
176
+ isValid: validation.isValid,
177
+ errors: validation.errors
178
+ });
179
+ return !validation.isValid;
60
180
  }
61
- async getTokenInfo(tokenId) {
62
- return await this.queryTokenInfo(tokenId);
181
+ /**
182
+ * Checks if input has bypass flags that skip form generation
183
+ */
184
+ hasFormBypassFlags(input) {
185
+ return input.__fromForm === true || input.renderForm === false;
63
186
  }
64
- async queryTokenInfo(tokenId) {
65
- try {
66
- this.logger.info("Querying token info using mirror node");
67
- const mirrorNode = this.agentKit.mirrorNode;
68
- if (!mirrorNode) {
69
- this.logger.info(
70
- "MirrorNode not found in agentKit, attempting to access via fetch"
187
+ /**
188
+ * Override _call to intercept tool execution
189
+ */
190
+ async _call(input, runManager) {
191
+ this.logger.info(`🚨🚨🚨 FormValidatingToolWrapper._call INTERCEPTING ${this.name} 🚨🚨🚨`, {
192
+ input,
193
+ inputKeys: Object.keys(input),
194
+ schemaShape: this.getSchemaShape(),
195
+ stackTrace: new Error().stack?.split("\n").slice(0, 5)
196
+ });
197
+ const inputRecord = input;
198
+ if (this.hasFormBypassFlags(inputRecord)) {
199
+ this.logger.info("Bypassing form generation and executing original tool due to submission flags");
200
+ return this.executeOriginal(inputRecord, runManager);
201
+ }
202
+ const shouldGenerate = this.shouldGenerateForm(input);
203
+ this.logger.info(`FormValidatingToolWrapper decision for ${this.name}:`, {
204
+ shouldGenerateForm: shouldGenerate,
205
+ toolName: this.name,
206
+ originalToolName: this.originalTool.name
207
+ });
208
+ if (shouldGenerate) {
209
+ this.logger.info(`Generating form for incomplete input in ${this.name}`);
210
+ try {
211
+ const isCustom = isFormValidatable(this.originalTool);
212
+ const schemaToUse = isCustom ? this.getFormSchema() : this.schema;
213
+ const missingFields = this.calculateMissingFields(
214
+ input,
215
+ isCustom
71
216
  );
72
- const network = this.agentKit.network || "testnet";
73
- const mirrorNodeUrl = network === "mainnet" ? "https://mainnet.mirrornode.hedera.com" : "https://testnet.mirrornode.hedera.com";
74
- const response = await fetch(
75
- `${mirrorNodeUrl}/api/v1/tokens/${tokenId}`
217
+ const schemaFields = this.isZodObject(schemaToUse) ? Object.keys(schemaToUse.shape) : [];
218
+ this.logger.info(`Using ${isCustom ? "CUSTOM" : "DEFAULT"} schema for form generation`, {
219
+ toolName: this.originalTool.name,
220
+ schemaType: schemaToUse.constructor?.name,
221
+ schemaFields,
222
+ isCustomSchema: isCustom
223
+ });
224
+ const formMessage = await this.createFormMessage(
225
+ schemaToUse,
226
+ input,
227
+ missingFields
76
228
  );
77
- if (response.ok) {
78
- const tokenData = await response.json();
79
- const decimals = parseInt(String(tokenData.decimals || "0"));
80
- this.logger.info(
81
- `Token ${tokenId} found with ${decimals} decimals via API`
82
- );
83
- return { ...tokenData, decimals };
84
- }
85
- } else {
86
- const tokenData = await mirrorNode.getTokenInfo(tokenId);
87
- if (tokenData && typeof tokenData.decimals !== "undefined") {
88
- const decimals = parseInt(tokenData.decimals.toString()) || 0;
89
- this.logger.info(`Token ${tokenId} found with ${decimals} decimals`);
90
- return { ...tokenData, decimals };
91
- }
229
+ const result = {
230
+ requiresForm: true,
231
+ formMessage,
232
+ message: `Please complete the form to provide the required information for ${this.name}.`
233
+ };
234
+ this.logger.info(`FormValidatingToolWrapper returning form result for ${this.name}`);
235
+ return JSON.stringify(result);
236
+ } catch (error) {
237
+ this.logger.error("Failed to generate form:", error);
92
238
  }
93
- throw new Error(`Token data not found or missing decimals field`);
94
- } catch (error) {
95
- this.logger.warn(`Failed to query token info for ${tokenId}:`, error);
96
- this.logger.info(
97
- "Falling back to assumed 0 decimal places (smallest units)"
98
- );
99
- return { decimals: 0 };
100
239
  }
240
+ this.logger.info(`FormValidatingToolWrapper passing through to original tool ${this.name}`);
241
+ return this.executeOriginal(input, runManager);
101
242
  }
102
243
  }
244
+ function wrapToolWithFormValidation(tool, formGenerator, config = {}) {
245
+ return new FormValidatingToolWrapper(tool, formGenerator, config);
246
+ }
103
247
  export {
104
- AirdropToolWrapper
248
+ FormValidatingToolWrapper,
249
+ wrapToolWithFormValidation
105
250
  };
106
251
  //# sourceMappingURL=index19.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index19.js","sources":["../../src/plugins/hbar/AirdropToolWrapper.ts"],"sourcesContent":["import { StructuredTool } from '@langchain/core/tools';\nimport { z } from 'zod';\nimport { HederaAgentKit } from 'hedera-agent-kit';\nimport { Logger } from '@hashgraphonline/standards-sdk';\n\ninterface TokenInfo {\n decimals: number;\n [key: string]: unknown;\n}\n\ninterface ToolWithCall {\n _call(input: unknown): Promise<string>;\n}\n\ninterface AgentKitWithMirrorNode {\n mirrorNode?: {\n getTokenInfo(tokenId: string): Promise<TokenInfo>;\n };\n network: string;\n}\n\nexport class AirdropToolWrapper extends StructuredTool {\n name = 'hedera-hts-airdrop-token';\n description =\n 'Airdrops fungible tokens to multiple recipients. Automatically converts human-readable amounts to smallest units based on token decimals.';\n\n schema = z.object({\n tokenId: z\n .string()\n .describe('The ID of the fungible token to airdrop (e.g., \"0.0.yyyy\").'),\n recipients: z\n .array(\n z.object({\n accountId: z\n .string()\n .describe('Recipient account ID (e.g., \"0.0.xxxx\").'),\n amount: z\n .union([z.number(), z.string()])\n .describe(\n 'Amount in human-readable format (e.g., \"10\" for 10 tokens).'\n ),\n })\n )\n .min(1)\n .describe('Array of recipient objects, each with accountId and amount.'),\n memo: z.string().optional().describe('Optional. Memo for the transaction.'),\n });\n\n private originalTool: StructuredTool & ToolWithCall;\n private agentKit: HederaAgentKit & AgentKitWithMirrorNode;\n private logger: Logger;\n\n constructor(originalTool: StructuredTool, agentKit: unknown) {\n super();\n this.originalTool = originalTool as StructuredTool & ToolWithCall;\n this.agentKit = agentKit as HederaAgentKit & AgentKitWithMirrorNode;\n this.logger = new Logger({ module: 'AirdropToolWrapper' });\n }\n\n async _call(input: z.infer<typeof this.schema>): Promise<string> {\n try {\n this.logger.info(\n `Processing airdrop request for token ${input.tokenId} with ${input.recipients.length} recipients`\n );\n\n const tokenInfo = await this.getTokenInfo(input.tokenId);\n const decimals = tokenInfo.decimals || 0;\n\n this.logger.info(`Token ${input.tokenId} has ${decimals} decimal places`);\n\n const convertedRecipients = input.recipients.map((recipient) => {\n const humanAmount =\n typeof recipient.amount === 'string'\n ? parseFloat(recipient.amount)\n : recipient.amount;\n const smallestUnitAmount = this.convertToSmallestUnits(\n humanAmount,\n decimals\n );\n\n this.logger.info(\n `Converting amount for ${recipient.accountId}: ${humanAmount} tokens → ${smallestUnitAmount} smallest units`\n );\n\n return {\n ...recipient,\n amount: smallestUnitAmount.toString(),\n };\n });\n\n const convertedInput = {\n ...input,\n recipients: convertedRecipients,\n };\n\n this.logger.info(`Calling original airdrop tool with converted amounts`);\n return await this.originalTool._call(convertedInput);\n } catch (error) {\n this.logger.error('Error in airdrop tool wrapper:', error);\n throw error;\n }\n }\n\n private convertToSmallestUnits(amount: number, decimals: number): number {\n return Math.floor(amount * Math.pow(10, decimals));\n }\n\n private async getTokenInfo(tokenId: string): Promise<TokenInfo> {\n return await this.queryTokenInfo(tokenId);\n }\n\n private async queryTokenInfo(tokenId: string): Promise<TokenInfo> {\n try {\n this.logger.info('Querying token info using mirror node');\n const mirrorNode = this.agentKit.mirrorNode;\n if (!mirrorNode) {\n this.logger.info(\n 'MirrorNode not found in agentKit, attempting to access via fetch'\n );\n const network = this.agentKit.network || 'testnet';\n const mirrorNodeUrl =\n network === 'mainnet'\n ? 'https://mainnet.mirrornode.hedera.com'\n : 'https://testnet.mirrornode.hedera.com';\n\n const response = await fetch(\n `${mirrorNodeUrl}/api/v1/tokens/${tokenId}`\n );\n if (response.ok) {\n const tokenData = (await response.json()) as Record<string, unknown>;\n const decimals = parseInt(String(tokenData.decimals || '0'));\n this.logger.info(\n `Token ${tokenId} found with ${decimals} decimals via API`\n );\n return { ...tokenData, decimals };\n }\n } else {\n const tokenData = await mirrorNode.getTokenInfo(tokenId);\n\n if (tokenData && typeof tokenData.decimals !== 'undefined') {\n const decimals = parseInt(tokenData.decimals.toString()) || 0;\n this.logger.info(`Token ${tokenId} found with ${decimals} decimals`);\n return { ...tokenData, decimals };\n }\n }\n\n throw new Error(`Token data not found or missing decimals field`);\n } catch (error) {\n this.logger.warn(`Failed to query token info for ${tokenId}:`, error);\n\n this.logger.info(\n 'Falling back to assumed 0 decimal places (smallest units)'\n );\n return { decimals: 0 };\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index19.js","sources":["../../src/langchain/FormValidatingToolWrapper.ts"],"sourcesContent":["import { StructuredTool } from '@langchain/core/tools';\nimport { z } from 'zod';\nimport { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';\nimport { Logger } from '@hashgraphonline/standards-sdk';\nimport { FormGenerator } from '../forms/form-generator';\nimport { isFormValidatable } from '@hashgraphonline/standards-agent-kit';\n\nexport interface FormValidationConfig {\n requireAllFields?: boolean;\n skipFields?: string[];\n customValidation?: (input: unknown) => boolean;\n}\n\n/**\n * Generic wrapper for StructuredTools that intercepts execution to check for missing required fields\n * and generates forms when validation would benefit from user input.\n *\n * Tools can implement the FormValidatable interface to provide custom validation logic.\n * Otherwise, falls back to schema-based validation.\n */\nexport class FormValidatingToolWrapper<\n TSchema extends z.ZodObject<z.ZodRawShape, z.UnknownKeysParam, z.ZodTypeAny>\n> extends StructuredTool<TSchema> {\n private originalTool: StructuredTool<TSchema>;\n private formGenerator: FormGenerator;\n private validationConfig: FormValidationConfig;\n private logger: Logger;\n\n name: string;\n description: string;\n schema: TSchema;\n\n constructor(\n originalTool: StructuredTool<TSchema>,\n formGenerator: FormGenerator,\n config: FormValidationConfig = {}\n ) {\n super();\n this.originalTool = originalTool;\n this.formGenerator = formGenerator;\n this.validationConfig = config;\n this.logger = new Logger({ module: 'FormValidatingToolWrapper' });\n\n this.name = originalTool.name;\n this.description = originalTool.description;\n this.schema = originalTool.schema;\n \n this.logger.info(`šŸ”§ FormValidatingToolWrapper created for tool: ${this.name}`, {\n originalToolName: originalTool.name,\n originalToolType: originalTool.constructor.name,\n wrapperType: this.constructor.name\n });\n }\n\n /**\n * Validate the input against the schema\n */\n private validateInput(input: Record<string, unknown>): { isValid: boolean; errors?: string[] } {\n try {\n this.schema.parse(input);\n return { isValid: true };\n } catch (error) {\n if (error instanceof z.ZodError) {\n const errors = error.errors\n .filter(err => {\n const fieldName = err.path[0] as string;\n return !this.validationConfig.skipFields?.includes(fieldName);\n })\n .map(err => `${err.path.join('.')}: ${err.message}`);\n return { isValid: false, errors };\n }\n return { isValid: false, errors: ['Validation failed'] };\n }\n }\n\n /**\n * Gets the shape keys from the schema if it's a ZodObject\n */\n private getSchemaShape(): string[] {\n if (this.isZodObject(this.schema)) {\n return Object.keys(this.schema.shape);\n }\n return [];\n }\n\n /**\n * Executes the wrapped tool's original implementation directly, bypassing wrapper logic.\n */\n public async executeOriginal(\n input: Record<string, unknown>,\n runManager?: CallbackManagerForToolRun\n ): Promise<string> {\n type CallableMethod = (\n args: Record<string, unknown>,\n runManager?: CallbackManagerForToolRun\n ) => Promise<string>;\n \n const tool = this.originalTool as unknown as Record<string, unknown>;\n \n if ('_call' in tool && typeof tool._call === 'function') {\n return (tool._call as CallableMethod)(input, runManager);\n }\n if ('call' in tool && typeof tool.call === 'function') {\n return (tool.call as CallableMethod)(input, runManager);\n }\n throw new Error('Original tool has no callable implementation');\n }\n\n /**\n * Provides access to the wrapped tool instance for executors that want to bypass the wrapper.\n */\n public getOriginalTool(): StructuredTool<TSchema> {\n return this.originalTool;\n }\n\n /**\n * Checks if tool implements FormValidatable method\n */\n private hasFormValidatableMethod<T>(\n tool: unknown,\n methodName: string\n ): tool is Record<string, T> {\n return (\n tool !== null &&\n typeof tool === 'object' &&\n methodName in tool &&\n typeof (tool as Record<string, unknown>)[methodName] === 'function'\n );\n }\n\n /**\n * Expose FormValidatable methods by delegating to the underlying tool when available.\n */\n public getFormSchema(): z.ZodSchema {\n if (this.hasFormValidatableMethod<() => z.ZodSchema>(this.originalTool, 'getFormSchema')) {\n return this.originalTool.getFormSchema();\n }\n return this.schema as z.ZodSchema;\n }\n\n public getEssentialFields(): string[] {\n if (this.hasFormValidatableMethod<() => string[]>(this.originalTool, 'getEssentialFields')) {\n return this.originalTool.getEssentialFields();\n }\n return [];\n }\n\n public isFieldEmpty(fieldName: string, value: unknown): boolean {\n if (this.hasFormValidatableMethod<(n: string, v: unknown) => boolean>(this.originalTool, 'isFieldEmpty')) {\n return this.originalTool.isFieldEmpty(fieldName, value);\n }\n if (value === undefined || value === null || value === '') {\n return true;\n }\n if (Array.isArray(value) && value.length === 0) {\n return true;\n }\n return false;\n }\n\n /**\n * Calculates which fields are missing from the input\n */\n private calculateMissingFields(\n input: Record<string, unknown>,\n isCustom: boolean\n ): Set<string> {\n const missingFields = new Set<string>();\n \n if (!isCustom) {\n return missingFields;\n }\n\n const essentialFields = this.getEssentialFields();\n for (const fieldName of essentialFields) {\n const value = input[fieldName];\n if (this.isFieldEmpty(fieldName, value)) {\n missingFields.add(fieldName);\n }\n }\n \n return missingFields;\n }\n\n /**\n * Creates a form message with optional JSON schema\n */\n private async createFormMessage(\n schema: z.ZodSchema,\n input: Record<string, unknown>,\n missingFields: Set<string>\n ) {\n let formMessage = await this.formGenerator.generateFormFromSchema(\n schema,\n input,\n {\n toolName: this.name,\n toolDescription: this.description\n },\n missingFields\n );\n\n if (this.isZodObject(schema)) {\n try {\n const { jsonSchema, uiSchema } = this.formGenerator.generateJsonSchemaForm(\n schema,\n input,\n missingFields\n );\n formMessage = {\n ...formMessage,\n jsonSchema,\n uiSchema\n };\n } catch (error) {\n this.logger.warn('Failed to generate JSON Schema for RJSF:', error);\n }\n }\n\n formMessage.partialInput = input;\n return formMessage;\n }\n\n /**\n * Type guard to check if a schema is a ZodObject\n */\n private isZodObject(schema: z.ZodSchema): schema is z.ZodObject<z.ZodRawShape> {\n const def = (schema as z.ZodType)._def as { typeName?: string };\n return !!(def && def.typeName === 'ZodObject');\n }\n\n /**\n * Check if we should generate a form for this tool invocation\n */\n private shouldGenerateForm(input: Record<string, unknown>): boolean {\n this.logger.info(`shouldGenerateForm called for ${this.name}/${this.originalTool.name}`, {\n input,\n hasCustomValidation: !!this.validationConfig.customValidation\n });\n\n if (this.validationConfig.customValidation) {\n const result = !this.validationConfig.customValidation(input);\n this.logger.info(`Custom validation result: ${result}`);\n return result;\n }\n\n if (isFormValidatable(this.originalTool)) {\n this.logger.info(`Tool ${this.originalTool.name} implements FormValidatable, using custom logic`);\n return this.originalTool.shouldGenerateForm(input);\n }\n\n this.logger.info(`Tool ${this.originalTool.name} using schema validation only`);\n const validation = this.validateInput(input);\n this.logger.info(`Schema validation for ${this.originalTool.name}:`, {\n isValid: validation.isValid,\n errors: validation.errors\n });\n return !validation.isValid;\n }\n\n /**\n * Checks if input has bypass flags that skip form generation\n */\n private hasFormBypassFlags(input: Record<string, unknown>): boolean {\n return (\n (input.__fromForm === true) ||\n (input.renderForm === false)\n );\n }\n\n /**\n * Override _call to intercept tool execution\n */\n protected async _call(\n input: z.infer<TSchema>,\n runManager?: CallbackManagerForToolRun\n ): Promise<string> {\n this.logger.info(`🚨🚨🚨 FormValidatingToolWrapper._call INTERCEPTING ${this.name} 🚨🚨🚨`, {\n input,\n inputKeys: Object.keys(input as Record<string, unknown>),\n schemaShape: this.getSchemaShape(),\n stackTrace: new Error().stack?.split('\\n').slice(0, 5)\n });\n\n const inputRecord = input as unknown as Record<string, unknown>;\n \n if (this.hasFormBypassFlags(inputRecord)) {\n this.logger.info('Bypassing form generation and executing original tool due to submission flags');\n return this.executeOriginal(inputRecord, runManager);\n }\n\n const shouldGenerate = this.shouldGenerateForm(input as Record<string, unknown>);\n this.logger.info(`FormValidatingToolWrapper decision for ${this.name}:`, {\n shouldGenerateForm: shouldGenerate,\n toolName: this.name,\n originalToolName: this.originalTool.name\n });\n\n if (shouldGenerate) {\n this.logger.info(`Generating form for incomplete input in ${this.name}`);\n\n try {\n const isCustom = isFormValidatable(this.originalTool);\n const schemaToUse = isCustom ? this.getFormSchema() : this.schema;\n const missingFields = this.calculateMissingFields(\n input as Record<string, unknown>,\n isCustom\n );\n\n const schemaFields = this.isZodObject(schemaToUse) \n ? Object.keys(schemaToUse.shape)\n : [];\n \n this.logger.info(`Using ${isCustom ? 'CUSTOM' : 'DEFAULT'} schema for form generation`, {\n toolName: this.originalTool.name,\n schemaType: schemaToUse.constructor?.name,\n schemaFields,\n isCustomSchema: isCustom\n });\n\n const formMessage = await this.createFormMessage(\n schemaToUse,\n input as Record<string, unknown>,\n missingFields\n );\n\n const result = {\n requiresForm: true,\n formMessage,\n message: `Please complete the form to provide the required information for ${this.name}.`\n };\n\n this.logger.info(`FormValidatingToolWrapper returning form result for ${this.name}`);\n return JSON.stringify(result);\n } catch (error) {\n this.logger.error('Failed to generate form:', error);\n }\n }\n\n this.logger.info(`FormValidatingToolWrapper passing through to original tool ${this.name}`);\n return this.executeOriginal(input as Record<string, unknown>, runManager);\n }\n\n}\n\n/**\n * Wrap a tool with form validation capabilities\n */\nexport function wrapToolWithFormValidation<TSchema extends z.ZodObject<z.ZodRawShape, z.UnknownKeysParam, z.ZodTypeAny>>(\n tool: StructuredTool<TSchema>,\n formGenerator: FormGenerator,\n config: FormValidationConfig = {}\n): FormValidatingToolWrapper<TSchema> {\n return new FormValidatingToolWrapper(tool, formGenerator, config);\n}"],"names":[],"mappings":"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"}
@@ -1,23 +1,117 @@
1
- const getSystemMessage = (accountId) => `You are a helpful assistant managing Hashgraph Online HCS-10 connections, messages, HCS-2 registries, content inscription, and Hedera Hashgraph operations.
1
+ class ResponseFormatter {
2
+ /**
3
+ * Checks if a parsed response contains HashLink block data for interactive rendering
4
+ */
5
+ static isHashLinkResponse(parsed) {
6
+ if (!parsed || typeof parsed !== "object") {
7
+ return false;
8
+ }
9
+ const responseObj = parsed;
10
+ return !!(responseObj.success === true && responseObj.type === "inscription" && responseObj.hashLinkBlock && typeof responseObj.hashLinkBlock === "object");
11
+ }
12
+ /**
13
+ * Formats HashLink block response with simple text confirmation
14
+ * HTML template rendering is handled by HashLinkBlockRenderer component via metadata
15
+ */
16
+ static formatHashLinkResponse(parsed) {
17
+ const hashLinkBlock = parsed.hashLinkBlock;
18
+ const metadata = parsed.metadata || {};
19
+ const inscription = parsed.inscription || {};
20
+ let message = "āœ… Interactive content created successfully!\n\n";
21
+ if (metadata.name) {
22
+ message += `**${metadata.name}**
23
+ `;
24
+ }
25
+ if (metadata.description) {
26
+ message += `${metadata.description}
2
27
 
3
- You have access to tools for:
4
- - HCS-10: registering agents, finding registered agents, initiating connections, listing active connections, sending messages over connections, and checking for new messages
5
- - HCS-2: creating registries, registering entries, updating entries, deleting entries, migrating registries, and querying registry contents
6
- - Inscription: inscribing content from URLs, files, or buffers, creating Hashinal NFTs, and retrieving inscriptions
7
- - Hedera Token Service (HTS): creating tokens, transferring tokens, airdropping tokens, and managing token operations
28
+ `;
29
+ }
30
+ if (inscription.topicId || hashLinkBlock.attributes.topicId) {
31
+ message += `šŸ“ **Topic ID:** ${inscription.topicId || hashLinkBlock.attributes.topicId}
32
+ `;
33
+ }
34
+ if (inscription.hrl || hashLinkBlock.attributes.hrl) {
35
+ message += `šŸ”— **HRL:** ${inscription.hrl || hashLinkBlock.attributes.hrl}
36
+ `;
37
+ }
38
+ if (inscription.cdnUrl) {
39
+ message += `🌐 **CDN URL:** ${inscription.cdnUrl}
40
+ `;
41
+ }
42
+ if (metadata.creator) {
43
+ message += `šŸ‘¤ **Creator:** ${metadata.creator}
44
+ `;
45
+ }
46
+ message += "\n⚔ Interactive content will load below";
47
+ return message.trim();
48
+ }
49
+ /**
50
+ * Checks if a parsed response is an inscription response that needs formatting
51
+ */
52
+ static isInscriptionResponse(parsed) {
53
+ if (!parsed || typeof parsed !== "object") {
54
+ return false;
55
+ }
56
+ const responseObj = parsed;
57
+ return !!(responseObj.success === true && responseObj.type === "inscription" && responseObj.inscription && typeof responseObj.inscription === "object");
58
+ }
59
+ /**
60
+ * Formats inscription response into user-friendly message
61
+ */
62
+ static formatInscriptionResponse(parsed) {
63
+ const inscription = parsed.inscription;
64
+ const metadata = parsed.metadata || {};
65
+ const title = parsed.title || "Inscription Complete";
66
+ let message = `āœ… ${title}
8
67
 
9
- *** IMPORTANT CONTEXT ***
10
- You are currently operating as agent: ${accountId} on the Hashgraph Online network
11
- When users ask about "my profile", "my account", "my connections", etc., use this account ID: ${accountId}
68
+ `;
69
+ if (metadata.name) {
70
+ message += `**${metadata.name}**
71
+ `;
72
+ }
73
+ if (metadata.description) {
74
+ message += `${metadata.description}
12
75
 
13
- *** CRITICAL ENTITY HANDLING RULES ***
14
- - When users refer to entities (tokens, topics, accounts) with pronouns like "it", "that", "the token/topic", etc., ALWAYS use the most recently created entity of that type
15
- - Entity IDs look like "0.0.XXXXXX" and are stored in memory after creation
16
- - NEVER use example or placeholder IDs like "0.0.123456" - always use actual created entity IDs
17
- - Account ID ${accountId} is NOT a token - tokens and accounts are different entities
18
-
19
- Remember the connection numbers when listing connections, as users might refer to them.`;
76
+ `;
77
+ }
78
+ if (inscription.topicId) {
79
+ message += `šŸ“ **Topic ID:** ${inscription.topicId}
80
+ `;
81
+ }
82
+ if (inscription.hrl) {
83
+ message += `šŸ”— **HRL:** ${inscription.hrl}
84
+ `;
85
+ }
86
+ if (inscription.cdnUrl) {
87
+ message += `🌐 **CDN URL:** ${inscription.cdnUrl}
88
+ `;
89
+ }
90
+ if (metadata.creator) {
91
+ message += `šŸ‘¤ **Creator:** ${metadata.creator}
92
+ `;
93
+ }
94
+ return message.trim();
95
+ }
96
+ /**
97
+ * Main formatting method that determines the best response format
98
+ */
99
+ static formatResponse(toolOutput) {
100
+ try {
101
+ const parsed = JSON.parse(toolOutput);
102
+ if (ResponseFormatter.isHashLinkResponse(parsed)) {
103
+ return ResponseFormatter.formatHashLinkResponse(parsed);
104
+ }
105
+ if (ResponseFormatter.isInscriptionResponse(parsed)) {
106
+ return ResponseFormatter.formatInscriptionResponse(parsed);
107
+ }
108
+ return toolOutput;
109
+ } catch {
110
+ return toolOutput;
111
+ }
112
+ }
113
+ }
20
114
  export {
21
- getSystemMessage
115
+ ResponseFormatter
22
116
  };
23
117
  //# sourceMappingURL=index20.js.map