@hashgraphonline/standards-agent-kit 0.2.121 → 0.2.123

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 (44) hide show
  1. package/dist/cjs/standards-agent-kit.cjs +1 -1
  2. package/dist/cjs/standards-agent-kit.cjs.map +1 -1
  3. package/dist/cjs/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
  4. package/dist/cjs/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
  5. package/dist/cjs/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
  6. package/dist/cjs/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
  7. package/dist/cjs/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
  8. package/dist/cjs/tools/inscriber/base-inscriber-tools.d.ts +15 -0
  9. package/dist/es/standards-agent-kit.es29.js +0 -2
  10. package/dist/es/standards-agent-kit.es29.js.map +1 -1
  11. package/dist/es/standards-agent-kit.es33.js +44 -0
  12. package/dist/es/standards-agent-kit.es33.js.map +1 -1
  13. package/dist/es/standards-agent-kit.es34.js +35 -6
  14. package/dist/es/standards-agent-kit.es34.js.map +1 -1
  15. package/dist/es/standards-agent-kit.es35.js +47 -9
  16. package/dist/es/standards-agent-kit.es35.js.map +1 -1
  17. package/dist/es/standards-agent-kit.es36.js +43 -6
  18. package/dist/es/standards-agent-kit.es36.js.map +1 -1
  19. package/dist/es/standards-agent-kit.es37.js +39 -6
  20. package/dist/es/standards-agent-kit.es37.js.map +1 -1
  21. package/dist/es/standards-agent-kit.es5.js +28 -4
  22. package/dist/es/standards-agent-kit.es5.js.map +1 -1
  23. package/dist/es/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
  24. package/dist/es/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
  25. package/dist/es/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
  26. package/dist/es/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
  27. package/dist/es/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
  28. package/dist/es/tools/inscriber/base-inscriber-tools.d.ts +15 -0
  29. package/dist/umd/standards-agent-kit.umd.js +1 -1
  30. package/dist/umd/standards-agent-kit.umd.js.map +1 -1
  31. package/dist/umd/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
  32. package/dist/umd/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
  33. package/dist/umd/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
  34. package/dist/umd/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
  35. package/dist/umd/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
  36. package/dist/umd/tools/inscriber/base-inscriber-tools.d.ts +15 -0
  37. package/package.json +31 -27
  38. package/src/builders/hcs6/hcs6-builder.ts +33 -4
  39. package/src/tools/hcs6/CreateDynamicRegistryTool.ts +4 -6
  40. package/src/tools/inscriber/InscribeFromBufferTool.ts +49 -9
  41. package/src/tools/inscriber/InscribeFromFileTool.ts +50 -8
  42. package/src/tools/inscriber/InscribeFromUrlTool.ts +40 -11
  43. package/src/tools/inscriber/InscribeHashinalTool.ts +43 -6
  44. package/src/tools/inscriber/base-inscriber-tools.ts +87 -0
@@ -40,6 +40,11 @@ const inscribeFromUrlSchema = z.object({
40
40
  .string()
41
41
  .optional()
42
42
  .describe('API key for inscription service'),
43
+ quoteOnly: z
44
+ .boolean()
45
+ .optional()
46
+ .default(false)
47
+ .describe('If true, returns a cost quote instead of executing the inscription'),
43
48
  });
44
49
 
45
50
 
@@ -48,7 +53,7 @@ const inscribeFromUrlSchema = z.object({
48
53
  */
49
54
  export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeFromUrlSchema> {
50
55
  name = 'inscribeFromUrl';
51
- description = 'ONLY for direct FILE DOWNLOAD URLs ending with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or ANY HTML content - it WILL FAIL. If you have already retrieved content from any source (including MCP tools), you MUST use inscribeFromBuffer instead. This tool downloads files from URLs - it does NOT inscribe content you already have. When asked to "inscribe it" after retrieving content, ALWAYS use inscribeFromBuffer with the actual content.';
56
+ description = 'ONLY for direct FILE DOWNLOAD URLs ending with file extensions (.pdf, .jpg, .png, .json, .zip). NEVER use for web pages, articles, or ANY HTML content - it WILL FAIL. If you have already retrieved content from any source (including MCP tools), you MUST use inscribeFromBuffer instead. This tool downloads files from URLs - it does NOT inscribe content you already have. When asked to "inscribe it" after retrieving content, ALWAYS use inscribeFromBuffer with the actual content. Set quoteOnly=true to get cost estimates without executing the inscription.';
52
57
 
53
58
  get specificInputSchema() {
54
59
  return inscribeFromUrlSchema;
@@ -86,7 +91,6 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
86
91
  const timeoutId = setTimeout(() => controller.abort(), 10000);
87
92
 
88
93
  try {
89
- // First try HEAD request
90
94
  const headResponse = await fetch(params.url, {
91
95
  method: 'HEAD',
92
96
  signal: controller.signal,
@@ -101,7 +105,6 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
101
105
  const contentType = headResponse.headers.get('content-type') || '';
102
106
  const contentLength = headResponse.headers.get('content-length');
103
107
 
104
- // Check if content type indicates HTML/web page
105
108
  const webPageContentTypes = [
106
109
  'text/html',
107
110
  'application/xhtml+xml',
@@ -120,7 +123,6 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
120
123
  throw new Error(`URL content is too small (${contentLength} bytes). Content must be at least 10 bytes.`);
121
124
  }
122
125
 
123
- // If HEAD doesn't provide content-type, do a partial GET to check
124
126
  if (!contentType || contentType === 'application/octet-stream') {
125
127
  console.log(`[InscribeFromUrlTool] Content-Type unclear, fetching first 1KB to verify...`);
126
128
 
@@ -142,7 +144,6 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
142
144
  const bytes = new Uint8Array(buffer);
143
145
  const text = new TextDecoder('utf-8', { fatal: false }).decode(bytes.slice(0, 512));
144
146
 
145
- // Check if it looks like HTML
146
147
  if (text.toLowerCase().includes('<!doctype html') ||
147
148
  text.toLowerCase().includes('<html') ||
148
149
  text.match(/<meta\s+[^>]*>/i) ||
@@ -155,7 +156,6 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
155
156
  if (getError instanceof Error && getError.message.includes('HTML content')) {
156
157
  throw getError;
157
158
  }
158
- // If partial GET fails, continue anyway
159
159
  console.log(`[InscribeFromUrlTool] Could not perform partial GET validation: ${getError instanceof Error ? getError.message : 'Unknown error'}`);
160
160
  }
161
161
  }
@@ -182,13 +182,40 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
182
182
  metadata: params.metadata,
183
183
  tags: params.tags,
184
184
  chunkSize: params.chunkSize,
185
- waitForConfirmation: params.waitForConfirmation ?? true,
185
+ waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),
186
186
  waitMaxAttempts: 10,
187
187
  waitIntervalMs: 3000,
188
188
  apiKey: params.apiKey,
189
189
  network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',
190
+ quoteOnly: params.quoteOnly,
190
191
  };
191
192
 
193
+ if (params.quoteOnly) {
194
+ try {
195
+ const quote = await this.generateInscriptionQuote(
196
+ { type: 'url', url: params.url },
197
+ options
198
+ );
199
+
200
+ return {
201
+ success: true,
202
+ quote: {
203
+ totalCostHbar: quote.totalCostHbar,
204
+ validUntil: quote.validUntil,
205
+ breakdown: quote.breakdown,
206
+ },
207
+ contentInfo: {
208
+ url: params.url,
209
+ },
210
+ message: `Quote generated for URL: ${params.url}\nTotal cost: ${quote.totalCostHbar} HBAR\nQuote valid until: ${new Date(quote.validUntil).toLocaleString()}`,
211
+ };
212
+ } catch (error) {
213
+ const errorMessage =
214
+ error instanceof Error ? error.message : 'Failed to generate inscription quote';
215
+ throw new Error(`Quote generation failed: ${errorMessage}`);
216
+ }
217
+ }
218
+
192
219
  try {
193
220
  let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;
194
221
 
@@ -214,13 +241,15 @@ export class InscribeFromUrlTool extends BaseInscriberQueryTool<typeof inscribeF
214
241
  );
215
242
  }
216
243
 
217
- if (result.confirmed) {
218
- const topicId = result.inscription?.topic_id || result.result.topicId;
244
+ if (result.confirmed && !result.quote) {
245
+ const topicId = result.inscription?.topic_id || (result.result as any).topicId;
219
246
  const network = options.network || 'testnet';
220
247
  const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;
221
- 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.`;
248
+ return `Successfully inscribed and confirmed content on the Hedera network!\n\nTransaction ID: ${(result.result as any).transactionId}\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\nView inscription: ${cdnUrl}` : ''}\n\nThe inscription is now available.`;
249
+ } else if (!result.quote && !result.confirmed) {
250
+ return `Successfully submitted inscription to the Hedera network!\n\nTransaction ID: ${(result.result as any).transactionId}\n\nThe inscription is processing and will be confirmed shortly.`;
222
251
  } else {
223
- return `Successfully submitted inscription to the Hedera network!\n\nTransaction ID: ${result.result.transactionId}\n\nThe inscription is processing and will be confirmed shortly.`;
252
+ return 'Inscription operation completed.';
224
253
  }
225
254
  } catch (error) {
226
255
  const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe from URL';
@@ -54,6 +54,11 @@ const inscribeHashinalSchema = z.object({
54
54
  .string()
55
55
  .optional()
56
56
  .describe('API key for inscription service'),
57
+ quoteOnly: z
58
+ .boolean()
59
+ .optional()
60
+ .default(false)
61
+ .describe('If true, returns a cost quote instead of executing the inscription'),
57
62
  });
58
63
 
59
64
 
@@ -62,7 +67,7 @@ const inscribeHashinalSchema = z.object({
62
67
  */
63
68
  export class InscribeHashinalTool extends BaseInscriberQueryTool<typeof inscribeHashinalSchema> {
64
69
  name = 'inscribeHashinal';
65
- description = 'Inscribe content as a Hashinal NFT on the Hedera network';
70
+ description = 'Inscribe content as a Hashinal NFT on the Hedera network. Set quoteOnly=true to get cost estimates without executing the inscription.';
66
71
 
67
72
  get specificInputSchema() {
68
73
  return inscribeHashinalSchema;
@@ -87,13 +92,43 @@ export class InscribeHashinalTool extends BaseInscriberQueryTool<typeof inscribe
87
92
  jsonFileURL: params.jsonFileURL,
88
93
  tags: params.tags,
89
94
  chunkSize: params.chunkSize,
90
- waitForConfirmation: params.waitForConfirmation ?? true,
95
+ waitForConfirmation: params.quoteOnly ? false : (params.waitForConfirmation ?? true),
91
96
  waitMaxAttempts: 10,
92
97
  waitIntervalMs: 3000,
93
98
  apiKey: params.apiKey,
94
99
  network: this.inscriberBuilder['hederaKit'].client.network.toString().includes('mainnet') ? 'mainnet' : 'testnet',
100
+ quoteOnly: params.quoteOnly,
95
101
  };
96
102
 
103
+ if (params.quoteOnly) {
104
+ try {
105
+ const quote = await this.generateInscriptionQuote(
106
+ { type: 'url', url: params.url },
107
+ options
108
+ );
109
+
110
+ return {
111
+ success: true,
112
+ quote: {
113
+ totalCostHbar: quote.totalCostHbar,
114
+ validUntil: quote.validUntil,
115
+ breakdown: quote.breakdown,
116
+ },
117
+ contentInfo: {
118
+ url: params.url,
119
+ name: params.name,
120
+ creator: params.creator,
121
+ type: params.type,
122
+ },
123
+ message: `Quote generated for Hashinal NFT: ${params.name}\nCreator: ${params.creator}\nTotal cost: ${quote.totalCostHbar} HBAR\nQuote valid until: ${new Date(quote.validUntil).toLocaleString()}`,
124
+ };
125
+ } catch (error) {
126
+ const errorMessage =
127
+ error instanceof Error ? error.message : 'Failed to generate inscription quote';
128
+ throw new Error(`Quote generation failed: ${errorMessage}`);
129
+ }
130
+ }
131
+
97
132
  try {
98
133
  let result: Awaited<ReturnType<typeof this.inscriberBuilder.inscribe>>;
99
134
 
@@ -119,13 +154,15 @@ export class InscribeHashinalTool extends BaseInscriberQueryTool<typeof inscribe
119
154
  );
120
155
  }
121
156
 
122
- if (result.confirmed) {
123
- const topicId = result.inscription?.topic_id || result.result.topicId;
157
+ if (result.confirmed && !result.quote) {
158
+ const topicId = result.inscription?.topic_id || (result.result as any).topicId;
124
159
  const network = options.network || 'testnet';
125
160
  const cdnUrl = topicId ? `https://kiloscribe.com/api/inscription-cdn/${topicId}?network=${network}` : null;
126
- return `Successfully inscribed and confirmed Hashinal NFT on the Hedera network!\n\nTransaction ID: ${result.result.transactionId}\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\nView inscription: ${cdnUrl}` : ''}\n\nThe Hashinal NFT is now available.`;
161
+ return `Successfully inscribed and confirmed Hashinal NFT on the Hedera network!\n\nTransaction ID: ${(result.result as any).transactionId}\nTopic ID: ${topicId || 'N/A'}${cdnUrl ? `\nView inscription: ${cdnUrl}` : ''}\n\nThe Hashinal NFT is now available.`;
162
+ } else if (!result.quote && !result.confirmed) {
163
+ return `Successfully submitted Hashinal NFT inscription to the Hedera network!\n\nTransaction ID: ${(result.result as any).transactionId}\n\nThe inscription is processing and will be confirmed shortly.`;
127
164
  } else {
128
- return `Successfully submitted Hashinal NFT inscription to the Hedera network!\n\nTransaction ID: ${result.result.transactionId}\n\nThe inscription is processing and will be confirmed shortly.`;
165
+ return 'Inscription operation completed.';
129
166
  }
130
167
  } catch (error) {
131
168
  const errorMessage = error instanceof Error ? error.message : 'Failed to inscribe Hashinal NFT';
@@ -9,6 +9,11 @@ import {
9
9
  InscriberQueryToolParams,
10
10
  } from './inscriber-tool-params';
11
11
  import type { ContentResolverInterface } from '../../types/content-resolver';
12
+ import {
13
+ InscriptionInput,
14
+ InscriptionOptions,
15
+ QuoteResult,
16
+ } from '@hashgraphonline/standards-sdk';
12
17
  import { z } from 'zod';
13
18
 
14
19
  /**
@@ -44,6 +49,47 @@ export abstract class BaseInscriberTransactionTool<
44
49
  protected getContentResolver(): ContentResolverInterface | null {
45
50
  return this.contentResolver;
46
51
  }
52
+
53
+ /**
54
+ * Generate a quote for an inscription without executing it
55
+ * @param input - The inscription input data
56
+ * @param options - Inscription options
57
+ * @returns Promise containing the quote result
58
+ */
59
+ protected async generateInscriptionQuote(
60
+ input: InscriptionInput,
61
+ options: InscriptionOptions
62
+ ): Promise<QuoteResult> {
63
+ const operatorId = this.inscriberBuilder['hederaKit'].signer.getAccountId().toString();
64
+ const operatorPrivateKey = this.inscriberBuilder['hederaKit'].signer?.getOperatorPrivateKey()
65
+ ? this.inscriberBuilder['hederaKit'].signer.getOperatorPrivateKey().toStringRaw()
66
+ : '';
67
+
68
+ const network = this.inscriberBuilder['hederaKit'].client.network;
69
+ const networkType = network.toString().includes('mainnet')
70
+ ? 'mainnet'
71
+ : 'testnet';
72
+
73
+ const clientConfig = {
74
+ accountId: operatorId,
75
+ privateKey: operatorPrivateKey,
76
+ network: networkType as 'mainnet' | 'testnet',
77
+ };
78
+
79
+ const quoteOptions = {
80
+ ...options,
81
+ quoteOnly: true,
82
+ network: networkType as 'mainnet' | 'testnet',
83
+ };
84
+
85
+ const result = await this.inscriberBuilder.inscribe(input, quoteOptions);
86
+
87
+ if (!result.quote || result.confirmed) {
88
+ throw new Error('Failed to generate quote - unexpected response type');
89
+ }
90
+
91
+ return result.result as QuoteResult;
92
+ }
47
93
  }
48
94
 
49
95
  /**
@@ -79,4 +125,45 @@ export abstract class BaseInscriberQueryTool<
79
125
  protected getContentResolver(): ContentResolverInterface | null {
80
126
  return this.contentResolver;
81
127
  }
128
+
129
+ /**
130
+ * Generate a quote for an inscription without executing it
131
+ * @param input - The inscription input data
132
+ * @param options - Inscription options
133
+ * @returns Promise containing the quote result
134
+ */
135
+ protected async generateInscriptionQuote(
136
+ input: InscriptionInput,
137
+ options: InscriptionOptions
138
+ ): Promise<QuoteResult> {
139
+ const operatorId = this.inscriberBuilder['hederaKit'].signer.getAccountId().toString();
140
+ const operatorPrivateKey = this.inscriberBuilder['hederaKit'].signer?.getOperatorPrivateKey()
141
+ ? this.inscriberBuilder['hederaKit'].signer.getOperatorPrivateKey().toStringRaw()
142
+ : '';
143
+
144
+ const network = this.inscriberBuilder['hederaKit'].client.network;
145
+ const networkType = network.toString().includes('mainnet')
146
+ ? 'mainnet'
147
+ : 'testnet';
148
+
149
+ const clientConfig = {
150
+ accountId: operatorId,
151
+ privateKey: operatorPrivateKey,
152
+ network: networkType as 'mainnet' | 'testnet',
153
+ };
154
+
155
+ const quoteOptions = {
156
+ ...options,
157
+ quoteOnly: true,
158
+ network: networkType as 'mainnet' | 'testnet',
159
+ };
160
+
161
+ const result = await this.inscriberBuilder.inscribe(input, quoteOptions);
162
+
163
+ if (!result.quote || result.confirmed) {
164
+ throw new Error('Failed to generate quote - unexpected response type');
165
+ }
166
+
167
+ return result.result as QuoteResult;
168
+ }
82
169
  }