@hashgraphonline/standards-agent-kit 0.2.103 → 0.2.104

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.
@@ -15,8 +15,8 @@ declare const inscribeFromBufferSchema: z.ZodObject<{
15
15
  waitForConfirmation: z.ZodOptional<z.ZodBoolean>;
16
16
  apiKey: z.ZodOptional<z.ZodString>;
17
17
  }, "strip", z.ZodTypeAny, {
18
- base64Data: string;
19
18
  fileName: string;
19
+ base64Data: string;
20
20
  tags?: string[] | undefined;
21
21
  metadata?: Record<string, unknown> | undefined;
22
22
  mode?: "file" | "hashinal" | undefined;
@@ -25,8 +25,8 @@ declare const inscribeFromBufferSchema: z.ZodObject<{
25
25
  apiKey?: string | undefined;
26
26
  mimeType?: string | undefined;
27
27
  }, {
28
- base64Data: string;
29
28
  fileName: string;
29
+ base64Data: string;
30
30
  tags?: string[] | undefined;
31
31
  metadata?: Record<string, unknown> | undefined;
32
32
  mode?: "file" | "hashinal" | undefined;
@@ -52,8 +52,8 @@ export declare class InscribeFromBufferTool extends BaseInscriberQueryTool<typeo
52
52
  waitForConfirmation: z.ZodOptional<z.ZodBoolean>;
53
53
  apiKey: z.ZodOptional<z.ZodString>;
54
54
  }, "strip", z.ZodTypeAny, {
55
- base64Data: string;
56
55
  fileName: string;
56
+ base64Data: string;
57
57
  tags?: string[] | undefined;
58
58
  metadata?: Record<string, unknown> | undefined;
59
59
  mode?: "file" | "hashinal" | undefined;
@@ -62,8 +62,8 @@ export declare class InscribeFromBufferTool extends BaseInscriberQueryTool<typeo
62
62
  apiKey?: string | undefined;
63
63
  mimeType?: string | undefined;
64
64
  }, {
65
- base64Data: string;
66
65
  fileName: string;
66
+ base64Data: string;
67
67
  tags?: string[] | undefined;
68
68
  metadata?: Record<string, unknown> | undefined;
69
69
  mode?: "file" | "hashinal" | undefined;
@@ -35,31 +35,9 @@ declare const inscribeFromFileSchema: z.ZodObject<{
35
35
  export declare class InscribeFromFileTool extends BaseInscriberQueryTool<typeof inscribeFromFileSchema> {
36
36
  name: string;
37
37
  description: string;
38
- get specificInputSchema(): z.ZodObject<{
39
- filePath: z.ZodString;
40
- mode: z.ZodOptional<z.ZodEnum<["file", "hashinal"]>>;
41
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
42
- tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
43
- chunkSize: z.ZodOptional<z.ZodNumber>;
44
- waitForConfirmation: z.ZodOptional<z.ZodBoolean>;
45
- apiKey: z.ZodOptional<z.ZodString>;
46
- }, "strip", z.ZodTypeAny, {
47
- filePath: string;
48
- tags?: string[] | undefined;
49
- metadata?: Record<string, unknown> | undefined;
50
- mode?: "file" | "hashinal" | undefined;
51
- chunkSize?: number | undefined;
52
- waitForConfirmation?: boolean | undefined;
53
- apiKey?: string | undefined;
54
- }, {
55
- filePath: string;
56
- tags?: string[] | undefined;
57
- metadata?: Record<string, unknown> | undefined;
58
- mode?: "file" | "hashinal" | undefined;
59
- chunkSize?: number | undefined;
60
- waitForConfirmation?: boolean | undefined;
61
- apiKey?: string | undefined;
62
- }>;
38
+ private logger;
39
+ get specificInputSchema(): typeof inscribeFromFileSchema;
63
40
  protected executeQuery(params: z.infer<typeof inscribeFromFileSchema>, _runManager?: CallbackManagerForToolRun): Promise<unknown>;
41
+ private getMimeType;
64
42
  }
65
43
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hashgraphonline/standards-agent-kit",
3
- "version": "0.2.103",
3
+ "version": "0.2.104",
4
4
  "description": "A modular SDK for building on-chain autonomous agents using Hashgraph Online Standards, including HCS-10 for agent discovery and communication.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/standards-agent-kit.cjs",
@@ -47,7 +47,7 @@ const inscribeFromBufferSchema = z.object({
47
47
  */
48
48
  export class InscribeFromBufferTool extends BaseInscriberQueryTool<typeof inscribeFromBufferSchema> {
49
49
  name = 'inscribeFromBuffer';
50
- description = 'Inscribe content from a buffer/base64 data to the Hedera network';
50
+ description = 'Inscribe content from a buffer/base64 data to the Hedera network. Useful for inscribing content that has been read into memory, including files accessed through MCP filesystem tools.';
51
51
 
52
52
  get specificInputSchema() {
53
53
  return inscribeFromBufferSchema;
@@ -57,7 +57,22 @@ export class InscribeFromBufferTool extends BaseInscriberQueryTool<typeof inscri
57
57
  params: z.infer<typeof inscribeFromBufferSchema>,
58
58
  _runManager?: CallbackManagerForToolRun
59
59
  ): Promise<unknown> {
60
+ console.log(`[InscribeFromBufferTool] Received base64Data length: ${params.base64Data?.length || 0}`);
61
+ console.log(`[InscribeFromBufferTool] fileName: ${params.fileName}`);
62
+ console.log(`[InscribeFromBufferTool] mimeType: ${params.mimeType}`);
63
+
64
+ if (!params.base64Data || params.base64Data.trim() === '') {
65
+ console.log(`[InscribeFromBufferTool] ERROR: No data provided`);
66
+ throw new Error('No data provided. Cannot inscribe empty content.');
67
+ }
68
+
60
69
  const buffer = Buffer.from(params.base64Data, 'base64');
70
+ console.log(`[InscribeFromBufferTool] Buffer length after conversion: ${buffer.length}`);
71
+
72
+ if (buffer.length === 0) {
73
+ console.log(`[InscribeFromBufferTool] ERROR: Buffer is empty after conversion`);
74
+ throw new Error('Buffer is empty. Cannot inscribe empty content.');
75
+ }
61
76
 
62
77
  const options: InscriptionOptions = {
63
78
  mode: params.mode,
@@ -1,7 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { BaseInscriberQueryTool } from './base-inscriber-tools';
3
- import { InscriptionOptions } from '@hashgraphonline/standards-sdk';
3
+ import { InscriptionOptions, Logger } from '@hashgraphonline/standards-sdk';
4
4
  import { CallbackManagerForToolRun } from '@langchain/core/callbacks/manager';
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
5
7
 
6
8
  /**
7
9
  * Schema for inscribing from file
@@ -30,21 +32,22 @@ const inscribeFromFileSchema = z.object({
30
32
  .boolean()
31
33
  .optional()
32
34
  .describe('Whether to wait for inscription confirmation'),
33
- apiKey: z
34
- .string()
35
- .optional()
36
- .describe('API key for inscription service'),
35
+ apiKey: z.string().optional().describe('API key for inscription service'),
37
36
  });
38
37
 
39
-
40
38
  /**
41
39
  * Tool for inscribing content from file
42
40
  */
43
- export class InscribeFromFileTool extends BaseInscriberQueryTool<typeof inscribeFromFileSchema> {
41
+ export class InscribeFromFileTool extends BaseInscriberQueryTool<
42
+ typeof inscribeFromFileSchema
43
+ > {
44
44
  name = 'inscribeFromFile';
45
- description = 'Inscribe content from a local file to the Hedera network';
45
+ description =
46
+ 'Inscribe content from a local file to the Hedera network using a file path. For files accessed through MCP filesystem tools, consider reading the file content first and using inscribeFromBuffer instead.';
47
+
48
+ private logger = new Logger({ module: 'InscribeFromFileTool' });
46
49
 
47
- get specificInputSchema() {
50
+ get specificInputSchema(): typeof inscribeFromFileSchema {
48
51
  return inscribeFromFileSchema;
49
52
  }
50
53
 
@@ -52,6 +55,51 @@ export class InscribeFromFileTool extends BaseInscriberQueryTool<typeof inscribe
52
55
  params: z.infer<typeof inscribeFromFileSchema>,
53
56
  _runManager?: CallbackManagerForToolRun
54
57
  ): Promise<unknown> {
58
+ // File validation
59
+ let fileContent: Buffer;
60
+ try {
61
+ this.logger.info(`Checking file: ${params.filePath}`);
62
+ this.logger.info(`Current working directory: ${process.cwd()}`);
63
+
64
+ const stats = await fs.stat(params.filePath);
65
+ if (!stats.isFile()) {
66
+ throw new Error(`Path "${params.filePath}" is not a file`);
67
+ }
68
+
69
+ this.logger.info(`File size: ${stats.size} bytes`);
70
+
71
+ if (stats.size === 0) {
72
+ throw new Error(
73
+ `File "${params.filePath}" is empty. Cannot inscribe empty files.`
74
+ );
75
+ }
76
+
77
+ this.logger.info('Reading file content...');
78
+ fileContent = await fs.readFile(params.filePath);
79
+ this.logger.info(`Read ${fileContent.length} bytes from file`);
80
+
81
+ if (!fileContent || fileContent.length === 0) {
82
+ throw new Error(
83
+ `File "${params.filePath}" has no content. Cannot inscribe empty files.`
84
+ );
85
+ }
86
+ } catch (error) {
87
+ if (error instanceof Error) {
88
+ if (error.message.includes('ENOENT')) {
89
+ throw new Error(`File not found: "${params.filePath}"`);
90
+ }
91
+ throw error;
92
+ }
93
+ throw new Error(`Failed to read file: ${error}`);
94
+ }
95
+
96
+ const base64Data = fileContent.toString('base64');
97
+ this.logger.info(`Converted to base64: ${base64Data.length} characters`);
98
+
99
+ const fileName = path.basename(params.filePath);
100
+ const mimeType = this.getMimeType(fileName);
101
+ this.logger.info(`File: ${fileName}, MIME type: ${mimeType}`);
102
+
55
103
  const options: InscriptionOptions = {
56
104
  mode: params.mode,
57
105
  metadata: params.metadata,
@@ -61,33 +109,76 @@ export class InscribeFromFileTool extends BaseInscriberQueryTool<typeof inscribe
61
109
  waitMaxAttempts: 10,
62
110
  waitIntervalMs: 3000,
63
111
  apiKey: params.apiKey,
64
- network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',
112
+ network: this.inscriberBuilder['hederaKit'].client.network
113
+ .toString()
114
+ .includes('mainnet')
115
+ ? 'mainnet'
116
+ : 'testnet',
65
117
  };
66
118
 
67
119
  try {
68
120
  const timeoutPromise = new Promise((_, reject) => {
69
- setTimeout(() => reject(new Error('Inscription timed out after 30 seconds')), 30000);
121
+ setTimeout(
122
+ () => reject(new Error('Inscription timed out after 30 seconds')),
123
+ 30000
124
+ );
70
125
  });
71
126
 
72
- const result = await Promise.race([
127
+ const result = (await Promise.race([
73
128
  this.inscriberBuilder.inscribe(
74
- { type: 'file', path: params.filePath },
129
+ {
130
+ type: 'buffer',
131
+ buffer: Buffer.from(base64Data, 'base64'),
132
+ fileName,
133
+ mimeType,
134
+ },
75
135
  options
76
136
  ),
77
- timeoutPromise
78
- ]) as any;
137
+ timeoutPromise,
138
+ ])) as any;
79
139
 
80
140
  if (result.confirmed) {
81
141
  const topicId = result.inscription?.topic_id || result.result.topicId;
82
142
  const network = options.network || 'testnet';
83
- const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;
84
- return `Successfully inscribed and confirmed content on the Hedera network!\n\nTransaction ID: ${result.result.transactionId}\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\nView inscription: ${cdnUrl}` : ''}\n\nThe inscription is now available.`;
143
+ const cdnUrl = topicId
144
+ ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}`
145
+ : null;
146
+ return `Successfully inscribed and confirmed content on the Hedera network!\n\nTransaction ID: ${
147
+ result.result.transactionId
148
+ }\nTopic ID: ${topicId || 'N/A'}${
149
+ cdnUrl ? `\nView inscription: ${cdnUrl}` : ''
150
+ }\n\nThe inscription is now available.`;
85
151
  } else {
86
152
  return `Successfully submitted inscription to the Hedera network!\n\nTransaction ID: ${result.result.transactionId}\n\nThe inscription is processing and will be confirmed shortly.`;
87
153
  }
88
154
  } catch (error) {
89
- const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe from file';
155
+ const errorMessage =
156
+ error instanceof Error ? error.message : 'Failed to inscribe from file';
90
157
  throw new Error(`Inscription failed: ${errorMessage}`);
91
158
  }
92
159
  }
93
- }
160
+
161
+ private getMimeType(fileName: string): string {
162
+ const ext = path.extname(fileName).toLowerCase();
163
+ const mimeTypes: Record<string, string> = {
164
+ '.png': 'image/png',
165
+ '.jpg': 'image/jpeg',
166
+ '.jpeg': 'image/jpeg',
167
+ '.gif': 'image/gif',
168
+ '.webp': 'image/webp',
169
+ '.svg': 'image/svg+xml',
170
+ '.pdf': 'application/pdf',
171
+ '.json': 'application/json',
172
+ '.txt': 'text/plain',
173
+ '.html': 'text/html',
174
+ '.css': 'text/css',
175
+ '.js': 'application/javascript',
176
+ '.ts': 'application/typescript',
177
+ '.mp4': 'video/mp4',
178
+ '.mp3': 'audio/mpeg',
179
+ '.wav': 'audio/wav',
180
+ '.zip': 'application/zip',
181
+ };
182
+ return mimeTypes[ext] || 'application/octet-stream';
183
+ }
184
+ }