@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.
- package/dist/cjs/standards-agent-kit.cjs +1 -1
- package/dist/cjs/standards-agent-kit.cjs.map +1 -1
- package/dist/cjs/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
- package/dist/cjs/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
- package/dist/cjs/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
- package/dist/cjs/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
- package/dist/cjs/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
- package/dist/cjs/tools/inscriber/base-inscriber-tools.d.ts +15 -0
- package/dist/es/standards-agent-kit.es29.js +0 -2
- package/dist/es/standards-agent-kit.es29.js.map +1 -1
- package/dist/es/standards-agent-kit.es33.js +44 -0
- package/dist/es/standards-agent-kit.es33.js.map +1 -1
- package/dist/es/standards-agent-kit.es34.js +35 -6
- package/dist/es/standards-agent-kit.es34.js.map +1 -1
- package/dist/es/standards-agent-kit.es35.js +47 -9
- package/dist/es/standards-agent-kit.es35.js.map +1 -1
- package/dist/es/standards-agent-kit.es36.js +43 -6
- package/dist/es/standards-agent-kit.es36.js.map +1 -1
- package/dist/es/standards-agent-kit.es37.js +39 -6
- package/dist/es/standards-agent-kit.es37.js.map +1 -1
- package/dist/es/standards-agent-kit.es5.js +28 -4
- package/dist/es/standards-agent-kit.es5.js.map +1 -1
- package/dist/es/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
- package/dist/es/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
- package/dist/es/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
- package/dist/es/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
- package/dist/es/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
- package/dist/es/tools/inscriber/base-inscriber-tools.d.ts +15 -0
- package/dist/umd/standards-agent-kit.umd.js +1 -1
- package/dist/umd/standards-agent-kit.umd.js.map +1 -1
- package/dist/umd/tools/hcs6/CreateDynamicRegistryTool.d.ts +0 -6
- package/dist/umd/tools/inscriber/InscribeFromBufferTool.d.ts +6 -0
- package/dist/umd/tools/inscriber/InscribeFromFileTool.d.ts +3 -0
- package/dist/umd/tools/inscriber/InscribeFromUrlTool.d.ts +6 -0
- package/dist/umd/tools/inscriber/InscribeHashinalTool.d.ts +6 -0
- package/dist/umd/tools/inscriber/base-inscriber-tools.d.ts +15 -0
- package/package.json +31 -27
- package/src/builders/hcs6/hcs6-builder.ts +33 -4
- package/src/tools/hcs6/CreateDynamicRegistryTool.ts +4 -6
- package/src/tools/inscriber/InscribeFromBufferTool.ts +49 -9
- package/src/tools/inscriber/InscribeFromFileTool.ts +50 -8
- package/src/tools/inscriber/InscribeFromUrlTool.ts +40 -11
- package/src/tools/inscriber/InscribeHashinalTool.ts +43 -6
- 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
|
|
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
|
|
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
|
}
|