@hashgraphonline/conversational-agent 0.1.215 → 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.
- package/dist/cjs/conversational-agent.d.ts +8 -0
- package/dist/cjs/core/ToolRegistry.d.ts +130 -0
- package/dist/cjs/execution/ExecutionPipeline.d.ts +81 -0
- package/dist/cjs/forms/FormEngine.d.ts +121 -0
- package/dist/cjs/forms/form-generator.d.ts +39 -2
- package/dist/cjs/forms/types.d.ts +21 -2
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +3 -4
- package/dist/cjs/langchain/FormAwareAgentExecutor.d.ts +53 -4
- package/dist/cjs/langchain/FormValidatingToolWrapper.d.ts +43 -6
- package/dist/cjs/langchain-agent.d.ts +49 -0
- package/dist/cjs/memory/ContentStorage.d.ts +7 -0
- package/dist/cjs/memory/SmartMemoryManager.d.ts +1 -0
- package/dist/cjs/services/ContentStoreManager.d.ts +11 -1
- package/dist/cjs/utils/ResponseFormatter.d.ts +26 -0
- package/dist/esm/index.js +2 -6
- package/dist/esm/index12.js +1 -1
- package/dist/esm/index12.js.map +1 -1
- package/dist/esm/index14.js +23 -5
- package/dist/esm/index14.js.map +1 -1
- package/dist/esm/index15.js +25 -4
- package/dist/esm/index15.js.map +1 -1
- package/dist/esm/index16.js +4 -2
- package/dist/esm/index16.js.map +1 -1
- package/dist/esm/index17.js +2 -7
- package/dist/esm/index17.js.map +1 -1
- package/dist/esm/index18.js +292 -150
- package/dist/esm/index18.js.map +1 -1
- package/dist/esm/index19.js +158 -65
- package/dist/esm/index19.js.map +1 -1
- package/dist/esm/index20.js +94 -270
- package/dist/esm/index20.js.map +1 -1
- package/dist/esm/index21.js +1 -1
- package/dist/esm/index23.js +14 -0
- package/dist/esm/index23.js.map +1 -1
- package/dist/esm/index24.js +508 -12
- package/dist/esm/index24.js.map +1 -1
- package/dist/esm/index25.js +1 -1
- package/dist/esm/index25.js.map +1 -1
- package/dist/esm/index26.js +1 -1
- package/dist/esm/index26.js.map +1 -1
- package/dist/esm/index27.js +189 -128
- package/dist/esm/index27.js.map +1 -1
- package/dist/esm/index28.js +164 -45
- package/dist/esm/index28.js.map +1 -1
- package/dist/esm/index29.js +302 -24
- package/dist/esm/index29.js.map +1 -1
- package/dist/esm/index30.js +144 -80
- package/dist/esm/index30.js.map +1 -1
- package/dist/esm/index31.js +63 -7
- package/dist/esm/index31.js.map +1 -1
- package/dist/esm/index32.js +24 -236
- package/dist/esm/index32.js.map +1 -1
- package/dist/esm/index33.js +95 -0
- package/dist/esm/index33.js.map +1 -0
- package/dist/esm/index34.js +245 -0
- package/dist/esm/index34.js.map +1 -0
- package/dist/esm/index5.js.map +1 -1
- package/dist/esm/index6.js +61 -22
- package/dist/esm/index6.js.map +1 -1
- package/dist/esm/index8.js +653 -131
- package/dist/esm/index8.js.map +1 -1
- package/dist/types/conversational-agent.d.ts +8 -0
- package/dist/types/core/ToolRegistry.d.ts +130 -0
- package/dist/types/execution/ExecutionPipeline.d.ts +81 -0
- package/dist/types/forms/FormEngine.d.ts +121 -0
- package/dist/types/forms/form-generator.d.ts +39 -2
- package/dist/types/forms/types.d.ts +21 -2
- package/dist/types/index.d.ts +3 -4
- package/dist/types/langchain/FormAwareAgentExecutor.d.ts +53 -4
- package/dist/types/langchain/FormValidatingToolWrapper.d.ts +43 -6
- package/dist/types/langchain-agent.d.ts +49 -0
- package/dist/types/memory/ContentStorage.d.ts +7 -0
- package/dist/types/memory/SmartMemoryManager.d.ts +1 -0
- package/dist/types/services/ContentStoreManager.d.ts +11 -1
- package/dist/types/utils/ResponseFormatter.d.ts +26 -0
- package/package.json +13 -10
- package/src/config/system-message.ts +14 -0
- package/src/context/ReferenceContextManager.ts +1 -1
- package/src/conversational-agent.ts +91 -36
- package/src/core/ToolRegistry.ts +358 -0
- package/src/execution/ExecutionPipeline.ts +301 -0
- package/src/forms/FormEngine.ts +443 -0
- package/src/forms/field-type-registry.ts +1 -13
- package/src/forms/form-generator.ts +394 -237
- package/src/forms/types.ts +20 -3
- package/src/index.ts +6 -10
- package/src/langchain/FormAwareAgentExecutor.ts +653 -22
- package/src/langchain/FormValidatingToolWrapper.ts +216 -93
- package/src/langchain-agent.ts +924 -185
- package/src/mcp/ContentProcessor.ts +20 -4
- package/src/mcp/MCPClientManager.ts +1 -1
- package/src/mcp/adapters/langchain.ts +1 -1
- package/src/memory/ContentStorage.ts +25 -5
- package/src/memory/SmartMemoryManager.ts +27 -4
- package/src/memory/TokenCounter.ts +1 -1
- package/src/plugins/hbar/HbarPlugin.ts +0 -1
- package/src/scripts/test-external-tool-wrapper.ts +3 -12
- package/src/scripts/test-hedera-kit-wrapper.ts +6 -22
- package/src/scripts/test-inscribe-form-generation.ts +24 -42
- package/src/scripts/test-inscribe-wrapper-verification.ts +1 -7
- package/src/services/ContentStoreManager.ts +23 -9
- package/src/services/EntityResolver.ts +2 -9
- package/src/tools/EntityResolverTool.ts +5 -8
- package/src/utils/ResponseFormatter.ts +146 -0
- package/dist/cjs/examples/external-tool-wrapper-example.d.ts +0 -131
- package/dist/cjs/langchain/ContentAwareAgentExecutor.d.ts +0 -14
- package/dist/cjs/langchain/external-tool-wrapper.d.ts +0 -179
- package/dist/cjs/scripts/test-external-tool-wrapper.d.ts +0 -5
- package/dist/cjs/scripts/test-hedera-kit-wrapper.d.ts +0 -36
- package/dist/cjs/scripts/test-inscribe-form-generation.d.ts +0 -15
- package/dist/cjs/scripts/test-inscribe-wrapper-verification.d.ts +0 -13
- package/dist/types/examples/external-tool-wrapper-example.d.ts +0 -131
- package/dist/types/langchain/ContentAwareAgentExecutor.d.ts +0 -14
- package/dist/types/langchain/external-tool-wrapper.d.ts +0 -179
- package/dist/types/scripts/test-external-tool-wrapper.d.ts +0 -5
- package/dist/types/scripts/test-hedera-kit-wrapper.d.ts +0 -36
- package/dist/types/scripts/test-inscribe-form-generation.d.ts +0 -15
- package/dist/types/scripts/test-inscribe-wrapper-verification.d.ts +0 -13
- package/src/examples/external-tool-wrapper-example.ts +0 -227
- package/src/langchain/ContentAwareAgentExecutor.ts +0 -19
- package/src/langchain/external-tool-wrapper.ts +0 -486
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z, ZodError } from 'zod';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
2
3
|
import type {
|
|
3
4
|
FormConfig,
|
|
4
5
|
FormField,
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
import { Logger } from '@hashgraphonline/standards-sdk';
|
|
17
18
|
import { fieldTypeRegistry } from './field-type-registry';
|
|
18
19
|
|
|
20
|
+
type FieldPriority = 'essential' | 'common' | 'advanced' | 'expert';
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
23
|
* Generates forms from Zod validation failures
|
|
21
24
|
*/
|
|
@@ -59,32 +62,58 @@ export class FormGenerator {
|
|
|
59
62
|
* @param schema The Zod schema to generate a form from
|
|
60
63
|
* @param partialInput Any partial input already provided
|
|
61
64
|
* @param context Additional context about the tool
|
|
65
|
+
* @param preCalculatedMissingFields Optional pre-calculated missing fields set. If undefined, includes all fields from schema.
|
|
62
66
|
* @returns FormMessage to send to the chat UI
|
|
63
67
|
*/
|
|
64
68
|
async generateFormFromSchema(
|
|
65
69
|
schema: z.ZodSchema,
|
|
66
|
-
partialInput:
|
|
67
|
-
context: { toolName: string; toolDescription?: string }
|
|
70
|
+
partialInput: unknown,
|
|
71
|
+
context: { toolName: string; toolDescription?: string },
|
|
72
|
+
preCalculatedMissingFields?: Set<string>
|
|
68
73
|
): Promise<FormMessage> {
|
|
69
|
-
|
|
74
|
+
let missingFields: Set<string>;
|
|
75
|
+
|
|
76
|
+
this.logger.info(`🏁 FormGenerator.generateFormFromSchema starting`, {
|
|
77
|
+
toolName: context.toolName,
|
|
78
|
+
partialInput,
|
|
79
|
+
hasSchema: !!schema,
|
|
80
|
+
hasShape: !!(schema && (schema as any).shape),
|
|
81
|
+
hasPreCalculatedFields: preCalculatedMissingFields !== undefined,
|
|
82
|
+
preCalculatedFieldsSize: preCalculatedMissingFields?.size || 0,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (preCalculatedMissingFields !== undefined) {
|
|
86
|
+
missingFields = preCalculatedMissingFields;
|
|
87
|
+
this.logger.info(`📋 Using pre-calculated missing fields`, {
|
|
88
|
+
missingFieldsCount: missingFields.size,
|
|
89
|
+
missingFields: Array.from(missingFields),
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
missingFields = new Set<string>();
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
partialInput[fieldName] === undefined ||
|
|
77
|
-
partialInput[fieldName] === ''
|
|
78
|
-
) {
|
|
94
|
+
const zodObject = this.extractZodObject(schema);
|
|
95
|
+
if (zodObject) {
|
|
96
|
+
const shape = zodObject.shape;
|
|
97
|
+
for (const fieldName of Object.keys(shape)) {
|
|
79
98
|
missingFields.add(fieldName);
|
|
99
|
+
this.logger.info(
|
|
100
|
+
`⭐ Including all fields from focused schema: ${fieldName}`
|
|
101
|
+
);
|
|
80
102
|
}
|
|
81
103
|
}
|
|
104
|
+
|
|
105
|
+
this.logger.info(`📋 Using ALL fields from focused schema`, {
|
|
106
|
+
totalFields: zodObject ? Object.keys(zodObject.shape).length : 0,
|
|
107
|
+
missingFieldsCount: missingFields.size,
|
|
108
|
+
missingFields: Array.from(missingFields),
|
|
109
|
+
});
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
const formConfig = this.createFormConfig(
|
|
85
113
|
schema,
|
|
86
114
|
missingFields,
|
|
87
|
-
context.toolName
|
|
115
|
+
context.toolName,
|
|
116
|
+
preCalculatedMissingFields
|
|
88
117
|
);
|
|
89
118
|
|
|
90
119
|
return {
|
|
@@ -113,7 +142,7 @@ export class FormGenerator {
|
|
|
113
142
|
*/
|
|
114
143
|
private identifyMissingFields(
|
|
115
144
|
errors: ValidationError[],
|
|
116
|
-
|
|
145
|
+
_schema: z.ZodSchema
|
|
117
146
|
): Set<string> {
|
|
118
147
|
const missingFields = new Set<string>();
|
|
119
148
|
|
|
@@ -133,7 +162,8 @@ export class FormGenerator {
|
|
|
133
162
|
private createFormConfig(
|
|
134
163
|
schema: z.ZodSchema,
|
|
135
164
|
missingFields: Set<string>,
|
|
136
|
-
toolName: string
|
|
165
|
+
toolName: string,
|
|
166
|
+
preCalculatedMissingFields?: Set<string>
|
|
137
167
|
): FormConfig {
|
|
138
168
|
const extractedConfig = this.extractRenderConfigsSafely(schema);
|
|
139
169
|
const fieldOrdering = this.generateFieldOrderingSafely(schema);
|
|
@@ -141,7 +171,8 @@ export class FormGenerator {
|
|
|
141
171
|
schema,
|
|
142
172
|
extractedConfig,
|
|
143
173
|
missingFields,
|
|
144
|
-
fieldOrdering
|
|
174
|
+
fieldOrdering,
|
|
175
|
+
preCalculatedMissingFields
|
|
145
176
|
);
|
|
146
177
|
|
|
147
178
|
return {
|
|
@@ -165,7 +196,7 @@ export class FormGenerator {
|
|
|
165
196
|
): ExtractedRenderConfig {
|
|
166
197
|
try {
|
|
167
198
|
if (typeof extractRenderConfigs === 'function') {
|
|
168
|
-
return extractRenderConfigs(schema as ZodSchemaWithRender);
|
|
199
|
+
return extractRenderConfigs(schema as unknown as ZodSchemaWithRender);
|
|
169
200
|
}
|
|
170
201
|
} catch (error) {
|
|
171
202
|
this.logger.warn('Could not extract render configs:', error);
|
|
@@ -186,8 +217,10 @@ export class FormGenerator {
|
|
|
186
217
|
} {
|
|
187
218
|
try {
|
|
188
219
|
if (typeof generateFieldOrdering === 'function') {
|
|
189
|
-
const ordering = generateFieldOrdering(
|
|
190
|
-
|
|
220
|
+
const ordering = generateFieldOrdering(
|
|
221
|
+
schema as unknown as ZodSchemaWithRender
|
|
222
|
+
);
|
|
223
|
+
|
|
191
224
|
const sections = Object.values(ordering.sections).map((section) => ({
|
|
192
225
|
fields: section.fields,
|
|
193
226
|
}));
|
|
@@ -200,78 +233,116 @@ export class FormGenerator {
|
|
|
200
233
|
}
|
|
201
234
|
|
|
202
235
|
/**
|
|
203
|
-
*
|
|
236
|
+
* Determines field priority for progressive disclosure
|
|
204
237
|
*/
|
|
205
|
-
private
|
|
238
|
+
private getFieldPriority(
|
|
239
|
+
name: string,
|
|
240
|
+
renderConfig?: RenderConfigSchema,
|
|
241
|
+
isRequired?: boolean
|
|
242
|
+
): FieldPriority {
|
|
243
|
+
if (renderConfig?.ui?.priority) {
|
|
244
|
+
const priority = renderConfig.ui.priority as string;
|
|
245
|
+
if (['essential', 'common', 'advanced', 'expert'].includes(priority)) {
|
|
246
|
+
return priority as FieldPriority;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (isRequired === true) {
|
|
251
|
+
return 'essential';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const ui = renderConfig?.ui as Record<string, unknown> | undefined;
|
|
255
|
+
if (ui?.advanced === true) {
|
|
256
|
+
return 'advanced';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (ui?.expert === true) {
|
|
260
|
+
return 'expert';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return 'common';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Determines which fields should be included in the form
|
|
268
|
+
*/
|
|
269
|
+
private determineFieldsToInclude(
|
|
206
270
|
schema: z.ZodSchema,
|
|
207
|
-
extractedConfig: ExtractedRenderConfig,
|
|
208
271
|
missingFields: Set<string>,
|
|
209
|
-
|
|
210
|
-
):
|
|
211
|
-
const
|
|
272
|
+
preCalculatedMissingFields?: Set<string>
|
|
273
|
+
): Set<string> {
|
|
274
|
+
const fieldsToInclude = new Set<string>();
|
|
212
275
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (expertFields.includes(name)) return 'expert';
|
|
238
|
-
|
|
239
|
-
// Keys and technical fields are advanced
|
|
240
|
-
if (
|
|
241
|
-
name.toLowerCase().includes('key') ||
|
|
242
|
-
name.includes('Period') ||
|
|
243
|
-
name.includes('Fees') ||
|
|
244
|
-
name.includes('autoRenew')
|
|
245
|
-
) {
|
|
246
|
-
return 'advanced';
|
|
247
|
-
}
|
|
276
|
+
if (preCalculatedMissingFields === undefined) {
|
|
277
|
+
this.logger.info(
|
|
278
|
+
`⭐ Focused schema mode - including ALL fields from schema`
|
|
279
|
+
);
|
|
280
|
+
const allSchemaFields = this.extractFieldsFromSchema(schema);
|
|
281
|
+
allSchemaFields.forEach((fieldName) => {
|
|
282
|
+
fieldsToInclude.add(fieldName);
|
|
283
|
+
this.logger.info(`✅ Including focused schema field: ${fieldName}`);
|
|
284
|
+
});
|
|
285
|
+
} else if (preCalculatedMissingFields.size > 0) {
|
|
286
|
+
this.logger.info(
|
|
287
|
+
`📋 Using ONLY pre-calculated missing fields (${preCalculatedMissingFields.size} fields)`,
|
|
288
|
+
{ fields: Array.from(preCalculatedMissingFields) }
|
|
289
|
+
);
|
|
290
|
+
preCalculatedMissingFields.forEach((fieldName) => {
|
|
291
|
+
fieldsToInclude.add(fieldName);
|
|
292
|
+
this.logger.info(`✅ Including pre-calculated field: ${fieldName}`);
|
|
293
|
+
});
|
|
294
|
+
} else {
|
|
295
|
+
this.logger.info(
|
|
296
|
+
'⚠️ No pre-calculated fields, falling back to schema analysis'
|
|
297
|
+
);
|
|
298
|
+
this.includeRequiredMissingFields(schema, missingFields, fieldsToInclude);
|
|
299
|
+
}
|
|
248
300
|
|
|
249
|
-
|
|
250
|
-
|
|
301
|
+
return fieldsToInclude;
|
|
302
|
+
}
|
|
251
303
|
|
|
252
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Includes required fields that are missing
|
|
306
|
+
*/
|
|
307
|
+
private includeRequiredMissingFields(
|
|
308
|
+
schema: z.ZodSchema,
|
|
309
|
+
missingFields: Set<string>,
|
|
310
|
+
fieldsToInclude: Set<string>
|
|
311
|
+
): void {
|
|
253
312
|
const allSchemaFields = this.extractFieldsFromSchema(schema);
|
|
254
|
-
const fieldsToInclude = new Set<string>();
|
|
255
|
-
|
|
256
313
|
allSchemaFields.forEach((fieldName) => {
|
|
257
|
-
const priority = getFieldPriority(fieldName);
|
|
258
314
|
const isRequired = this.isFieldRequired(schema, fieldName);
|
|
315
|
+
const isMissing = missingFields.has(fieldName);
|
|
316
|
+
const shouldInclude = isMissing && isRequired;
|
|
259
317
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
)
|
|
318
|
+
this.logger.info(`🔍 FormGenerator field inclusion check: ${fieldName}`, {
|
|
319
|
+
isRequired,
|
|
320
|
+
isMissing,
|
|
321
|
+
shouldInclude,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
if (shouldInclude) {
|
|
265
325
|
fieldsToInclude.add(fieldName);
|
|
266
326
|
}
|
|
267
327
|
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Creates form fields from ordered field names
|
|
332
|
+
*/
|
|
333
|
+
private createOrderedFields(
|
|
334
|
+
fieldsToInclude: Set<string>,
|
|
335
|
+
fieldOrdering: { sections: Array<{ fields: string[] }> },
|
|
336
|
+
extractedConfig: ExtractedRenderConfig,
|
|
337
|
+
schema: z.ZodSchema
|
|
338
|
+
): FormField[] {
|
|
339
|
+
const fields: FormField[] = [];
|
|
340
|
+
const processedFields = new Set<string>();
|
|
268
341
|
|
|
269
|
-
// If we have field ordering from render configs, use that first
|
|
270
342
|
if (fieldOrdering.sections.length > 0) {
|
|
271
343
|
const orderedFieldNames = fieldOrdering.sections.flatMap((s) => s.fields);
|
|
272
|
-
|
|
273
344
|
orderedFieldNames.forEach((fieldName) => {
|
|
274
|
-
if (fieldsToInclude.has(fieldName)) {
|
|
345
|
+
if (fieldsToInclude.has(fieldName) && !processedFields.has(fieldName)) {
|
|
275
346
|
const field = this.createFormField(
|
|
276
347
|
fieldName,
|
|
277
348
|
extractedConfig.fields[fieldName],
|
|
@@ -280,15 +351,14 @@ export class FormGenerator {
|
|
|
280
351
|
);
|
|
281
352
|
if (field) {
|
|
282
353
|
fields.push(field);
|
|
354
|
+
processedFields.add(fieldName);
|
|
283
355
|
}
|
|
284
356
|
}
|
|
285
357
|
});
|
|
286
358
|
}
|
|
287
359
|
|
|
288
|
-
// Add any remaining fields not in ordering
|
|
289
360
|
fieldsToInclude.forEach((fieldName) => {
|
|
290
|
-
|
|
291
|
-
if (!fields.some((f) => f.name === fieldName)) {
|
|
361
|
+
if (!processedFields.has(fieldName)) {
|
|
292
362
|
const field = this.createFormField(
|
|
293
363
|
fieldName,
|
|
294
364
|
extractedConfig.fields[fieldName],
|
|
@@ -301,19 +371,45 @@ export class FormGenerator {
|
|
|
301
371
|
}
|
|
302
372
|
});
|
|
303
373
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
374
|
+
return fields;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Generates form fields from schema and validation errors
|
|
379
|
+
*/
|
|
380
|
+
private generateFormFields(
|
|
381
|
+
schema: z.ZodSchema,
|
|
382
|
+
extractedConfig: ExtractedRenderConfig,
|
|
383
|
+
missingFields: Set<string>,
|
|
384
|
+
fieldOrdering: { sections: Array<{ fields: string[] }> },
|
|
385
|
+
preCalculatedMissingFields?: Set<string>
|
|
386
|
+
): FormField[] {
|
|
387
|
+
const fieldsToInclude = this.determineFieldsToInclude(
|
|
388
|
+
schema,
|
|
389
|
+
missingFields,
|
|
390
|
+
preCalculatedMissingFields
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
let fields = this.createOrderedFields(
|
|
394
|
+
fieldsToInclude,
|
|
395
|
+
fieldOrdering,
|
|
396
|
+
extractedConfig,
|
|
397
|
+
schema
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
if (fields.length === 0 && missingFields.size > 0) {
|
|
401
|
+
fields = Array.from(missingFields)
|
|
402
|
+
.map((fieldName) =>
|
|
403
|
+
this.createFormField(
|
|
404
|
+
fieldName,
|
|
405
|
+
extractedConfig.fields[fieldName],
|
|
406
|
+
schema,
|
|
407
|
+
fieldName
|
|
408
|
+
)
|
|
409
|
+
)
|
|
410
|
+
.filter(
|
|
411
|
+
(field): field is FormField => field !== null && field !== undefined
|
|
312
412
|
);
|
|
313
|
-
if (field) {
|
|
314
|
-
fields.push(field);
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
413
|
}
|
|
318
414
|
|
|
319
415
|
return fields;
|
|
@@ -329,47 +425,6 @@ export class FormGenerator {
|
|
|
329
425
|
fieldPath?: string
|
|
330
426
|
): FormField {
|
|
331
427
|
const type = this.mapFieldType(renderConfig?.fieldType, schema, fieldPath);
|
|
332
|
-
|
|
333
|
-
// Determine field priority for progressive disclosure
|
|
334
|
-
const getFieldPriority = (
|
|
335
|
-
name: string
|
|
336
|
-
): 'essential' | 'common' | 'advanced' | 'expert' => {
|
|
337
|
-
const essentialFields = [
|
|
338
|
-
'tokenSymbol',
|
|
339
|
-
'treasuryAccountId',
|
|
340
|
-
'maxSupply',
|
|
341
|
-
'tokenName',
|
|
342
|
-
'name',
|
|
343
|
-
'description',
|
|
344
|
-
'contentRef',
|
|
345
|
-
];
|
|
346
|
-
const commonFields = ['creator', 'type', 'fileStandard', 'supplyType'];
|
|
347
|
-
const expertFields = [
|
|
348
|
-
'apiKey',
|
|
349
|
-
'chunkSize',
|
|
350
|
-
'timeoutMs',
|
|
351
|
-
'quoteOnly',
|
|
352
|
-
'waitForConfirmation',
|
|
353
|
-
];
|
|
354
|
-
|
|
355
|
-
if (essentialFields.includes(name)) return 'essential';
|
|
356
|
-
if (commonFields.includes(name)) return 'common';
|
|
357
|
-
if (expertFields.includes(name)) return 'expert';
|
|
358
|
-
|
|
359
|
-
// Keys and technical fields are advanced
|
|
360
|
-
if (
|
|
361
|
-
name.toLowerCase().includes('key') ||
|
|
362
|
-
name.includes('Period') ||
|
|
363
|
-
name.includes('Fees') ||
|
|
364
|
-
name.includes('autoRenew')
|
|
365
|
-
) {
|
|
366
|
-
return 'advanced';
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return 'advanced'; // Default to advanced for unknown fields
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
// Determine if field is required from schema
|
|
373
428
|
const isRequired = this.isFieldRequired(schema, fieldPath || fieldName);
|
|
374
429
|
|
|
375
430
|
const field: FormField = {
|
|
@@ -377,7 +432,7 @@ export class FormGenerator {
|
|
|
377
432
|
label: renderConfig?.ui?.label || this.humanizeFieldName(fieldName),
|
|
378
433
|
type,
|
|
379
434
|
required: isRequired,
|
|
380
|
-
priority: getFieldPriority(fieldName),
|
|
435
|
+
priority: this.getFieldPriority(fieldName, renderConfig, isRequired),
|
|
381
436
|
};
|
|
382
437
|
|
|
383
438
|
if (renderConfig) {
|
|
@@ -429,7 +484,6 @@ export class FormGenerator {
|
|
|
429
484
|
schema?: z.ZodSchema,
|
|
430
485
|
fieldPath?: string
|
|
431
486
|
): FormFieldType {
|
|
432
|
-
// First try schema inference if no explicit fieldType
|
|
433
487
|
if (!fieldType && schema && fieldPath) {
|
|
434
488
|
const inferredType = this.inferTypeFromSchema(schema, fieldPath);
|
|
435
489
|
if (inferredType) {
|
|
@@ -437,7 +491,6 @@ export class FormGenerator {
|
|
|
437
491
|
}
|
|
438
492
|
}
|
|
439
493
|
|
|
440
|
-
// If no fieldType and schema inference failed, use registry pattern detection
|
|
441
494
|
if (!fieldType && fieldPath) {
|
|
442
495
|
const registryType = fieldTypeRegistry.detectType(fieldPath);
|
|
443
496
|
if (registryType) {
|
|
@@ -498,24 +551,45 @@ export class FormGenerator {
|
|
|
498
551
|
return `Complete ${cleanName} Information`;
|
|
499
552
|
}
|
|
500
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Safely extracts ZodObject from a schema, returns null if not an object schema
|
|
556
|
+
*/
|
|
557
|
+
private extractZodObject(
|
|
558
|
+
schema: z.ZodSchema
|
|
559
|
+
): z.ZodObject<z.ZodRawShape> | null {
|
|
560
|
+
try {
|
|
561
|
+
const def = (schema as z.ZodType)._def as { typeName?: string };
|
|
562
|
+
if (def && def.typeName === 'ZodObject') {
|
|
563
|
+
return schema as z.ZodObject<z.ZodRawShape>;
|
|
564
|
+
}
|
|
565
|
+
} catch (error) {
|
|
566
|
+
this.logger.debug('Could not extract ZodObject from schema:', error);
|
|
567
|
+
}
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
|
|
501
571
|
/**
|
|
502
572
|
* Extracts field names from Zod schema structure
|
|
503
573
|
*/
|
|
504
574
|
private extractFieldsFromSchema(schema: z.ZodSchema): string[] {
|
|
505
575
|
const fields: string[] = [];
|
|
506
576
|
|
|
577
|
+
const zodObject = this.extractZodObject(schema);
|
|
578
|
+
if (zodObject) {
|
|
579
|
+
fields.push(...Object.keys(zodObject.shape));
|
|
580
|
+
return fields;
|
|
581
|
+
}
|
|
582
|
+
|
|
507
583
|
try {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
fields.push(...Object.keys(firstOption._def.shape));
|
|
518
|
-
}
|
|
584
|
+
const def = (schema as z.ZodType)._def as {
|
|
585
|
+
typeName?: string;
|
|
586
|
+
options?: z.ZodType[];
|
|
587
|
+
};
|
|
588
|
+
if (def && def.typeName === 'ZodUnion' && def.options) {
|
|
589
|
+
const firstOption = def.options[0];
|
|
590
|
+
const firstOptionObject = this.extractZodObject(firstOption);
|
|
591
|
+
if (firstOptionObject) {
|
|
592
|
+
fields.push(...Object.keys(firstOptionObject.shape));
|
|
519
593
|
}
|
|
520
594
|
}
|
|
521
595
|
} catch (error) {
|
|
@@ -536,67 +610,58 @@ export class FormGenerator {
|
|
|
536
610
|
fieldPath: string
|
|
537
611
|
): FormFieldType | null {
|
|
538
612
|
try {
|
|
539
|
-
const
|
|
613
|
+
const zodObject = this.extractZodObject(schema);
|
|
614
|
+
if (!zodObject) return null;
|
|
540
615
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
if (typeof def.shape === 'function') {
|
|
544
|
-
shape = def.shape();
|
|
545
|
-
} else {
|
|
546
|
-
shape = def.shape;
|
|
547
|
-
}
|
|
616
|
+
const shape = zodObject.shape;
|
|
617
|
+
if (!shape) return null;
|
|
548
618
|
|
|
549
|
-
|
|
550
|
-
|
|
619
|
+
let fieldSchema = shape[fieldPath] as z.ZodType | undefined;
|
|
620
|
+
if (!fieldSchema) return null;
|
|
551
621
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
622
|
+
const fieldDef = fieldSchema._def as {
|
|
623
|
+
typeName?: string;
|
|
624
|
+
innerType?: z.ZodType;
|
|
625
|
+
};
|
|
626
|
+
if (
|
|
627
|
+
fieldDef &&
|
|
628
|
+
fieldDef.typeName === 'ZodOptional' &&
|
|
629
|
+
fieldDef.innerType
|
|
630
|
+
) {
|
|
631
|
+
fieldSchema = fieldDef.innerType;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (!fieldSchema || !fieldSchema._def) return null;
|
|
560
635
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
fieldPath.toLowerCase().includes('description')
|
|
570
|
-
) {
|
|
571
|
-
return 'textarea';
|
|
572
|
-
}
|
|
573
|
-
return 'text';
|
|
574
|
-
case 'ZodNumber':
|
|
575
|
-
// Check for special number patterns
|
|
576
|
-
if (fieldPath.toLowerCase().includes('percent')) {
|
|
577
|
-
return 'percentage';
|
|
578
|
-
}
|
|
579
|
-
if (
|
|
580
|
-
fieldPath.toLowerCase().includes('price') ||
|
|
581
|
-
fieldPath.toLowerCase().includes('cost')
|
|
582
|
-
) {
|
|
583
|
-
return 'currency';
|
|
584
|
-
}
|
|
585
|
-
return 'number';
|
|
586
|
-
case 'ZodBoolean':
|
|
587
|
-
return 'checkbox';
|
|
588
|
-
case 'ZodEnum':
|
|
589
|
-
case 'ZodNativeEnum':
|
|
590
|
-
return 'select';
|
|
591
|
-
case 'ZodArray':
|
|
592
|
-
return 'array';
|
|
593
|
-
case 'ZodObject':
|
|
594
|
-
return 'object';
|
|
595
|
-
default:
|
|
596
|
-
return 'text';
|
|
597
|
-
}
|
|
636
|
+
const typeDef = fieldSchema._def as { typeName?: string };
|
|
637
|
+
const fieldTypeName = typeDef.typeName;
|
|
638
|
+
const lowerPath = fieldPath.toLowerCase();
|
|
639
|
+
|
|
640
|
+
switch (fieldTypeName) {
|
|
641
|
+
case 'ZodString':
|
|
642
|
+
if (lowerPath.includes('memo') || lowerPath.includes('description')) {
|
|
643
|
+
return 'textarea';
|
|
598
644
|
}
|
|
599
|
-
|
|
645
|
+
return 'text';
|
|
646
|
+
case 'ZodNumber':
|
|
647
|
+
if (lowerPath.includes('percent')) {
|
|
648
|
+
return 'percentage';
|
|
649
|
+
}
|
|
650
|
+
if (lowerPath.includes('price') || lowerPath.includes('cost')) {
|
|
651
|
+
return 'currency';
|
|
652
|
+
}
|
|
653
|
+
return 'number';
|
|
654
|
+
case 'ZodBoolean':
|
|
655
|
+
return 'checkbox';
|
|
656
|
+
case 'ZodEnum':
|
|
657
|
+
case 'ZodNativeEnum':
|
|
658
|
+
return 'select';
|
|
659
|
+
case 'ZodArray':
|
|
660
|
+
return 'array';
|
|
661
|
+
case 'ZodObject':
|
|
662
|
+
return 'object';
|
|
663
|
+
default:
|
|
664
|
+
return 'text';
|
|
600
665
|
}
|
|
601
666
|
} catch (error) {
|
|
602
667
|
this.logger.debug('Could not infer type from schema:', error);
|
|
@@ -609,53 +674,38 @@ export class FormGenerator {
|
|
|
609
674
|
*/
|
|
610
675
|
private isFieldRequired(schema?: z.ZodSchema, fieldPath?: string): boolean {
|
|
611
676
|
if (!schema || !fieldPath) {
|
|
612
|
-
return false;
|
|
677
|
+
return false;
|
|
613
678
|
}
|
|
614
679
|
|
|
615
680
|
try {
|
|
616
|
-
const
|
|
681
|
+
const zodObject = this.extractZodObject(schema);
|
|
682
|
+
if (!zodObject) return false;
|
|
617
683
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if (typeof def.shape === 'function') {
|
|
621
|
-
shape = def.shape();
|
|
622
|
-
} else {
|
|
623
|
-
shape = def.shape;
|
|
624
|
-
}
|
|
684
|
+
const shape = zodObject.shape;
|
|
685
|
+
if (!shape || !shape[fieldPath]) return false;
|
|
625
686
|
|
|
626
|
-
|
|
627
|
-
|
|
687
|
+
const fieldSchema = shape[fieldPath] as z.ZodType;
|
|
688
|
+
if (!fieldSchema || !fieldSchema._def) return true;
|
|
628
689
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
) {
|
|
635
|
-
return false; // Optional field
|
|
636
|
-
}
|
|
690
|
+
const fieldDef = fieldSchema._def as {
|
|
691
|
+
typeName?: string;
|
|
692
|
+
defaultValue?: unknown;
|
|
693
|
+
};
|
|
694
|
+
const typeName = fieldDef.typeName;
|
|
637
695
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
fieldSchema._def &&
|
|
642
|
-
fieldSchema._def.defaultValue !== undefined
|
|
643
|
-
) {
|
|
644
|
-
return false; // Has default, so optional
|
|
645
|
-
}
|
|
696
|
+
if (typeName === 'ZodOptional') {
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
646
699
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
fieldSchema._def &&
|
|
651
|
-
fieldSchema._def.typeName === 'ZodDefault'
|
|
652
|
-
) {
|
|
653
|
-
return false; // Has default, so optional
|
|
654
|
-
}
|
|
700
|
+
if (typeName === 'ZodDefault') {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
655
703
|
|
|
656
|
-
|
|
657
|
-
|
|
704
|
+
if (fieldDef.defaultValue !== undefined) {
|
|
705
|
+
return false;
|
|
658
706
|
}
|
|
707
|
+
|
|
708
|
+
return true;
|
|
659
709
|
} catch (error) {
|
|
660
710
|
this.logger.debug(
|
|
661
711
|
`Could not determine if field ${fieldPath} is required:`,
|
|
@@ -663,7 +713,7 @@ export class FormGenerator {
|
|
|
663
713
|
);
|
|
664
714
|
}
|
|
665
715
|
|
|
666
|
-
return false;
|
|
716
|
+
return false;
|
|
667
717
|
}
|
|
668
718
|
|
|
669
719
|
/**
|
|
@@ -681,4 +731,111 @@ export class FormGenerator {
|
|
|
681
731
|
fieldCount !== 1 ? 's' : ''
|
|
682
732
|
} to continue with your request.`;
|
|
683
733
|
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Generates JSON Schema and uiSchema from a Zod schema for use with @rjsf/core
|
|
737
|
+
* @param zodSchema The Zod schema to convert
|
|
738
|
+
* @param partialInput Existing input data to filter out fields that already have values
|
|
739
|
+
* @param missingFields Set of fields that are missing and should be shown
|
|
740
|
+
* @returns Object containing jsonSchema and uiSchema
|
|
741
|
+
*/
|
|
742
|
+
public generateJsonSchemaForm(
|
|
743
|
+
zodSchema: z.ZodObject<z.ZodRawShape>,
|
|
744
|
+
partialInput?: Record<string, unknown>,
|
|
745
|
+
missingFields?: Set<string>
|
|
746
|
+
) {
|
|
747
|
+
const fullJsonSchema = zodToJsonSchema(zodSchema, {
|
|
748
|
+
target: 'jsonSchema7',
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const uiSchema: Record<string, Record<string, unknown>> = {};
|
|
752
|
+
|
|
753
|
+
let jsonSchema = fullJsonSchema;
|
|
754
|
+
if (missingFields && missingFields.size > 0) {
|
|
755
|
+
const fullSchemaAsObject = fullJsonSchema as {
|
|
756
|
+
properties?: Record<string, unknown>;
|
|
757
|
+
required?: string[];
|
|
758
|
+
[key: string]: unknown;
|
|
759
|
+
};
|
|
760
|
+
if (
|
|
761
|
+
fullSchemaAsObject.properties &&
|
|
762
|
+
typeof fullSchemaAsObject.properties === 'object'
|
|
763
|
+
) {
|
|
764
|
+
const filteredSchema = {
|
|
765
|
+
...fullSchemaAsObject,
|
|
766
|
+
type: 'object' as const,
|
|
767
|
+
properties: {} as Record<string, unknown>,
|
|
768
|
+
required: [] as string[],
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
let fieldsAdded = 0;
|
|
772
|
+
missingFields.forEach((fieldName) => {
|
|
773
|
+
if (
|
|
774
|
+
fullSchemaAsObject.properties &&
|
|
775
|
+
fullSchemaAsObject.properties[fieldName]
|
|
776
|
+
) {
|
|
777
|
+
filteredSchema.properties[fieldName] =
|
|
778
|
+
fullSchemaAsObject.properties[fieldName];
|
|
779
|
+
fieldsAdded++;
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
if (Array.isArray(fullSchemaAsObject.required)) {
|
|
784
|
+
filteredSchema.required = fullSchemaAsObject.required.filter(
|
|
785
|
+
(field: string) => missingFields.has(field)
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (fieldsAdded > 0) {
|
|
790
|
+
jsonSchema = filteredSchema;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const fieldNames = this.extractFieldsFromSchema(zodSchema);
|
|
796
|
+
|
|
797
|
+
fieldNames.forEach((fieldName) => {
|
|
798
|
+
const isRequired = this.isFieldRequired(zodSchema, fieldName);
|
|
799
|
+
const priority = this.getFieldPriority(fieldName, undefined, isRequired);
|
|
800
|
+
const lower = fieldName.toLowerCase();
|
|
801
|
+
|
|
802
|
+
if (
|
|
803
|
+
lower === 'attributes' ||
|
|
804
|
+
lower === 'metadata' ||
|
|
805
|
+
lower === 'properties'
|
|
806
|
+
) {
|
|
807
|
+
uiSchema[fieldName] = {
|
|
808
|
+
'ui:options': {
|
|
809
|
+
collapsible: true,
|
|
810
|
+
collapsed: true,
|
|
811
|
+
},
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
switch (priority) {
|
|
816
|
+
case 'essential':
|
|
817
|
+
if (isRequired) {
|
|
818
|
+
uiSchema[fieldName] = {
|
|
819
|
+
...uiSchema[fieldName],
|
|
820
|
+
'ui:help': 'Required field',
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case 'advanced':
|
|
825
|
+
case 'expert':
|
|
826
|
+
uiSchema[fieldName] = {
|
|
827
|
+
...uiSchema[fieldName],
|
|
828
|
+
'ui:options': {
|
|
829
|
+
...(uiSchema[fieldName]?.['ui:options'] as
|
|
830
|
+
| Record<string, unknown>
|
|
831
|
+
| undefined),
|
|
832
|
+
collapsed: true,
|
|
833
|
+
},
|
|
834
|
+
};
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
return { jsonSchema, uiSchema };
|
|
840
|
+
}
|
|
684
841
|
}
|