UNPKG

@hashgraphonline/conversational-agent

Version:

Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera. https://hol.org

151 lines (128 loc) 4.27 kB
import { BaseHederaQueryTool, HederaAgentKit, type GenericPluginContext, } from "hedera-agent-kit"; import { Bee, CollectionUploadOptions } from "@ethersphere/bee-js"; import { z } from "zod"; import { promisify } from "util"; import fs from "fs"; import { errorHasStatus, getErrorMessage, getResponseWithStructuredContent, getUploadPostageBatchId, ToolResponse, } from "../utils"; import { BAD_REQUEST_STATUS } from "../constants"; import { SwarmConfig } from "../config"; const UploadFolderSchema = z.object({ folderPath: z.string(), redundancyLevel: z.number().optional(), postageBatchId: z.string().optional(), }); export class UploadFolderTool extends BaseHederaQueryTool<typeof UploadFolderSchema> { name = "swarm-upload-folder"; description = `Upload a folder to Swarm. folderPath: Path to the folder to upload. redundancyLevel: Redundancy level for fault tolerance (higher values provide better fault tolerance but increase storage overhead). 0 - none, 1 - medium, 2 - strong, 3 - insane, 4 - paranoid. postageBatchId: The postage stamp batch ID which will be used to perform the upload, if it is provided.`; namespace = "swarm"; specificInputSchema = UploadFolderSchema; bee: Bee; config: SwarmConfig; constructor(params: { hederaKit: HederaAgentKit; config: SwarmConfig; logger?: GenericPluginContext['logger']; bee: Bee; }) { const { bee, config, ...rest } = params; super(rest); this.bee = bee; this.config = config; } protected async executeQuery( input: z.infer<typeof UploadFolderSchema> ): Promise<ToolResponse | string> { const { folderPath, redundancyLevel: inputRedundancyLevel, postageBatchId: inputPostageBatchId } = input; if (!folderPath) { this.logger.error( 'Missing required parameter: folderPath.' ); throw new Error('Missing required parameter: folderPath.'); } // Check if folder exists const stats = await promisify(fs.stat)(folderPath); if (!stats.isDirectory()) { this.logger.error( `Path is not a directory: ${folderPath}.` ); throw new Error(`Path is not a directory: ${folderPath}.`); } let postageBatchId = ""; try { postageBatchId = await getUploadPostageBatchId( inputPostageBatchId, this.bee, this.config, ); } catch (error) { let errorMessage = 'Upload folder failed.'; if (error instanceof Error) { errorMessage = error.message; } this.logger.error(errorMessage); throw new Error(errorMessage); } const redundancyLevel = inputRedundancyLevel; const options: CollectionUploadOptions = {}; if (redundancyLevel) { options.redundancyLevel = redundancyLevel; } const deferred = true; options.deferred = deferred; let message = 'Folder successfully uploaded to Swarm'; let tagId: string | undefined = undefined; if (deferred) { try { const tag = await this.bee.createTag(); tagId = tag.uid.toString(); options.tag = tag.uid; message = 'Folder upload started in deferred mode. Use swarm-query-upload-progress to track progress.'; } catch (error) { this.logger.error( 'Failed to create tag', error ); options.deferred = false; } } let result; try { // Start the deferred upload result = await this.bee.uploadFilesFromDirectory( postageBatchId, folderPath, options ); } catch (error) { let errorMessage = 'Unable to upload folder.'; if (errorHasStatus(error, BAD_REQUEST_STATUS)) { errorMessage = getErrorMessage(error); } this.logger.error( errorMessage, error ); throw new Error(errorMessage); } return getResponseWithStructuredContent({ reference: result.reference.toString(), url: this.bee.url + "/bzz/" + result.reference.toString(), message, tagId, }); } }