@hashgraphonline/conversational-agent 0.2.1 → 0.2.101
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/README.md +3 -3
- package/dist/cjs/conversational-agent.d.ts +11 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/services/attachment-processor.d.ts +41 -0
- package/dist/cjs/services/index.d.ts +2 -0
- package/dist/cjs/services/parameter-service.d.ts +43 -0
- package/dist/cjs/tools/entity-resolver-tool.d.ts +5 -3
- package/dist/esm/index.js +9 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index10.js +2 -2
- package/dist/esm/index21.js +1 -1
- package/dist/esm/index23.js +3 -3
- package/dist/esm/index24.js +20 -4
- package/dist/esm/index24.js.map +1 -1
- package/dist/esm/index29.js +248 -903
- package/dist/esm/index29.js.map +1 -1
- package/dist/esm/index30.js +98 -219
- package/dist/esm/index30.js.map +1 -1
- package/dist/esm/index31.js +834 -1085
- package/dist/esm/index31.js.map +1 -1
- package/dist/esm/index32.js +228 -115
- package/dist/esm/index32.js.map +1 -1
- package/dist/esm/index33.js +1185 -79
- package/dist/esm/index33.js.map +1 -1
- package/dist/esm/index34.js +119 -39
- package/dist/esm/index34.js.map +1 -1
- package/dist/esm/index35.js +103 -96
- package/dist/esm/index35.js.map +1 -1
- package/dist/esm/index36.js +46 -21
- package/dist/esm/index36.js.map +1 -1
- package/dist/esm/index37.js +107 -12
- package/dist/esm/index37.js.map +1 -1
- package/dist/esm/index38.js +21 -7
- package/dist/esm/index38.js.map +1 -1
- package/dist/esm/index39.js +4 -26
- package/dist/esm/index39.js.map +1 -1
- package/dist/esm/index40.js +11 -4
- package/dist/esm/index40.js.map +1 -1
- package/dist/esm/index41.js +1 -1
- package/dist/esm/index43.js +24 -89
- package/dist/esm/index43.js.map +1 -1
- package/dist/esm/index44.js +10 -0
- package/dist/esm/index44.js.map +1 -0
- package/dist/esm/index45.js +95 -0
- package/dist/esm/index45.js.map +1 -0
- package/dist/esm/index5.js +2 -2
- package/dist/esm/index6.js +76 -6
- package/dist/esm/index6.js.map +1 -1
- package/dist/esm/index8.js +1 -1
- package/dist/types/conversational-agent.d.ts +11 -1
- package/dist/types/services/attachment-processor.d.ts +41 -0
- package/dist/types/services/index.d.ts +2 -0
- package/dist/types/services/parameter-service.d.ts +43 -0
- package/dist/types/tools/entity-resolver-tool.d.ts +5 -3
- package/package.json +2 -1
- package/src/conversational-agent.ts +97 -5
- package/src/langchain/langchain-agent.ts +9 -1
- package/src/services/attachment-processor.ts +163 -0
- package/src/services/content-store-manager.ts +32 -4
- package/src/services/index.ts +2 -0
- package/src/services/parameter-service.ts +430 -0
- package/src/tools/entity-resolver-tool.ts +12 -18
package/dist/esm/index29.js
CHANGED
|
@@ -1,964 +1,309 @@
|
|
|
1
|
-
import { AgentExecutor } from "langchain/agents";
|
|
2
|
-
import { z, ZodError } from "zod";
|
|
3
|
-
import { FormGenerator } from "./index10.js";
|
|
4
|
-
import { FormEngine } from "./index11.js";
|
|
5
1
|
import { Logger } from "@hashgraphonline/standards-sdk";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
this.formGenerator = new FormGenerator();
|
|
14
|
-
this.formEngine = new FormEngine(
|
|
15
|
-
new Logger({ module: "FormAwareAgentExecutor.FormEngine" })
|
|
16
|
-
);
|
|
17
|
-
this.formLogger = new Logger({ module: "FormAwareAgentExecutor" });
|
|
18
|
-
this.parameterPreprocessingCallback = void 0;
|
|
2
|
+
import { EntityFormat } from "./index26.js";
|
|
3
|
+
import "./index28.js";
|
|
4
|
+
class ParameterService {
|
|
5
|
+
constructor(formatConverterRegistry, networkType) {
|
|
6
|
+
this.logger = new Logger({ module: "ParameterService" });
|
|
7
|
+
this.formatConverterRegistry = formatConverterRegistry;
|
|
8
|
+
this.networkType = networkType;
|
|
19
9
|
}
|
|
20
10
|
/**
|
|
21
|
-
*
|
|
11
|
+
* Unified preprocessing entrypoint (DRY):
|
|
12
|
+
* - Optional AI-driven resolution via provided entityResolver
|
|
13
|
+
* - Deterministic post-pass for safe format enforcement
|
|
22
14
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
hasHashLinkBlock(metadata) {
|
|
30
|
-
return typeof metadata === "object" && metadata !== null && "hashLinkBlock" in metadata && typeof metadata.hashLinkBlock === "object" && metadata.hashLinkBlock !== null;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Set parameter preprocessing callback
|
|
34
|
-
*/
|
|
35
|
-
setParameterPreprocessingCallback(callback) {
|
|
36
|
-
this.parameterPreprocessingCallback = callback;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* BULLETPROOF TOOL INTERCEPTION
|
|
40
|
-
* Override the single-step execution to intercept tool calls BEFORE LangChain processes them
|
|
41
|
-
*/
|
|
42
|
-
async _takeNextStep(nameToolMap, inputs, intermediateSteps, runManager, config) {
|
|
43
|
-
this.formLogger.info("🛡️ BULLETPROOF INTERCEPTION: _takeNextStep called", {
|
|
44
|
-
availableTools: Object.keys(nameToolMap),
|
|
45
|
-
inputKeys: Object.keys(inputs)
|
|
46
|
-
});
|
|
47
|
-
const result = await this.agent.plan(
|
|
48
|
-
intermediateSteps,
|
|
49
|
-
inputs,
|
|
50
|
-
runManager?.getChild()
|
|
51
|
-
);
|
|
52
|
-
if ("returnValues" in result) {
|
|
53
|
-
this.formLogger.info("Agent returned finish action, passing through");
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
56
|
-
const action = result;
|
|
57
|
-
const toolName = action.tool;
|
|
58
|
-
const toolInput = action.toolInput;
|
|
59
|
-
this.formLogger.info(`🎯 INTERCEPTING TOOL CALL: ${toolName}`, {
|
|
60
|
-
toolInput,
|
|
61
|
-
hasInNameToolMap: toolName in nameToolMap,
|
|
62
|
-
toolInputKeys: Object.keys(toolInput || {})
|
|
63
|
-
});
|
|
64
|
-
const tool = nameToolMap[toolName] || this.tools.find((t) => t.name === toolName);
|
|
65
|
-
if (!tool) {
|
|
66
|
-
this.formLogger.error(`Tool ${toolName} not found in registry`);
|
|
67
|
-
throw new Error(`Tool "${toolName}" not found`);
|
|
68
|
-
}
|
|
69
|
-
let shouldGenerateForm = false;
|
|
70
|
-
if (isFormValidatable(tool)) {
|
|
71
|
-
this.formLogger.info(
|
|
72
|
-
`🔍 Tool ${toolName} implements FormValidatable, checking shouldGenerateForm()`,
|
|
73
|
-
{
|
|
74
|
-
toolInput
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
try {
|
|
78
|
-
shouldGenerateForm = tool.shouldGenerateForm(toolInput);
|
|
79
|
-
this.formLogger.info(
|
|
80
|
-
`FormValidatable.shouldGenerateForm() result: ${shouldGenerateForm}`,
|
|
81
|
-
{
|
|
82
|
-
toolName,
|
|
83
|
-
toolInput
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
} catch (error) {
|
|
87
|
-
this.formLogger.error(
|
|
88
|
-
`Error calling shouldGenerateForm() on ${toolName}:`,
|
|
89
|
-
error
|
|
90
|
-
);
|
|
91
|
-
shouldGenerateForm = false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (shouldGenerateForm) {
|
|
95
|
-
this.formLogger.info(`🚨 FORM GENERATION TRIGGERED for ${toolName}`);
|
|
15
|
+
async preprocessParameters(toolName, parameters, entities = [], options) {
|
|
16
|
+
const sessionId = options?.sessionId;
|
|
17
|
+
const entityResolver = options?.entityResolver;
|
|
18
|
+
const preferences = options?.preferences;
|
|
19
|
+
let working = { ...parameters };
|
|
20
|
+
if (entityResolver && entities.length > 0) {
|
|
96
21
|
try {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.formLogger.info(
|
|
109
|
-
`✅ Successfully obtained focused schema for ${toolName}`
|
|
110
|
-
);
|
|
111
|
-
} else {
|
|
112
|
-
this.formLogger.warn(
|
|
113
|
-
`getFormSchema() returned null/undefined for ${toolName}, using default schema`
|
|
114
|
-
);
|
|
115
|
-
schemaToUse = tool.schema;
|
|
116
|
-
isFocusedSchema = false;
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
this.formLogger.error(
|
|
120
|
-
`Failed to get focused schema from ${toolName}:`,
|
|
121
|
-
error
|
|
22
|
+
this.logger.info("AI-driven preprocessing phase", {
|
|
23
|
+
toolName,
|
|
24
|
+
entityCount: entities.length,
|
|
25
|
+
sessionId
|
|
26
|
+
});
|
|
27
|
+
const aiProcessed = { ...working };
|
|
28
|
+
for (const [paramName, paramValue] of Object.entries(working)) {
|
|
29
|
+
if (typeof paramValue === "string") {
|
|
30
|
+
const resolved = await entityResolver.resolveReferences(
|
|
31
|
+
paramValue,
|
|
32
|
+
entities
|
|
122
33
|
);
|
|
123
|
-
this.
|
|
124
|
-
|
|
34
|
+
const converted = await this.convertParameterEntities(
|
|
35
|
+
resolved,
|
|
36
|
+
entities,
|
|
37
|
+
preferences
|
|
125
38
|
);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
} catch {
|
|
146
|
-
}
|
|
147
|
-
this.formLogger.info(
|
|
148
|
-
`📋 Generating form with ${isFocusedSchema ? "FOCUSED" : "DEFAULT"} schema`,
|
|
149
|
-
{
|
|
150
|
-
toolName,
|
|
151
|
-
schemaType: schemaToUse?.constructor?.name,
|
|
152
|
-
estimatedFieldCount: schemaFieldCount,
|
|
153
|
-
isFocusedSchema
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
let missingFields;
|
|
157
|
-
if (isFocusedSchema) {
|
|
158
|
-
this.formLogger.info(
|
|
159
|
-
`⭐ Using focused schema - letting FormGenerator determine fields from schema`
|
|
160
|
-
);
|
|
161
|
-
missingFields = void 0;
|
|
162
|
-
} else {
|
|
163
|
-
missingFields = /* @__PURE__ */ new Set();
|
|
164
|
-
if (this.isZodObject(schemaToUse)) {
|
|
165
|
-
const zodObject = schemaToUse;
|
|
166
|
-
const shape = zodObject.shape || {};
|
|
167
|
-
for (const fieldName of Object.keys(shape)) {
|
|
168
|
-
const value = (toolInput || {})[fieldName];
|
|
169
|
-
const isEmpty = isFormValidatable(tool) && tool.isFieldEmpty ? tool.isFieldEmpty(fieldName, value) : value === void 0 || value === "" || value === null || Array.isArray(value) && value.length === 0;
|
|
170
|
-
const isRequired = this.isFieldRequired(schemaToUse, fieldName);
|
|
171
|
-
const isEssential = isFormValidatable(tool) && tool.getEssentialFields ? tool.getEssentialFields().includes(fieldName) : false;
|
|
172
|
-
this.formLogger.info(`🔍 Field analysis: ${fieldName}`, {
|
|
173
|
-
value,
|
|
174
|
-
isEmpty,
|
|
175
|
-
isRequired,
|
|
176
|
-
isEssential,
|
|
177
|
-
willAddToMissingFields: isEmpty && (isRequired || isEssential)
|
|
178
|
-
});
|
|
179
|
-
if (isEmpty && (isRequired || isEssential)) {
|
|
180
|
-
missingFields.add(fieldName);
|
|
39
|
+
aiProcessed[paramName] = converted;
|
|
40
|
+
} else if (Array.isArray(paramValue)) {
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const item of paramValue) {
|
|
43
|
+
if (typeof item === "string") {
|
|
44
|
+
const resolved = await entityResolver.resolveReferences(
|
|
45
|
+
item,
|
|
46
|
+
entities
|
|
47
|
+
);
|
|
48
|
+
const converted = await this.convertParameterEntities(
|
|
49
|
+
resolved,
|
|
50
|
+
entities,
|
|
51
|
+
preferences
|
|
52
|
+
);
|
|
53
|
+
out.push(converted);
|
|
54
|
+
} else {
|
|
55
|
+
out.push(item);
|
|
181
56
|
}
|
|
182
57
|
}
|
|
183
|
-
|
|
184
|
-
this.formLogger.info(`📋 Missing fields analysis complete`, {
|
|
185
|
-
totalFields: this.isZodObject(schemaToUse) ? Object.keys(schemaToUse.shape).length : 0,
|
|
186
|
-
missingFieldsCount: missingFields.size,
|
|
187
|
-
missingFields: Array.from(missingFields)
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
const formMessage = await this.formGenerator.generateFormFromSchema(
|
|
191
|
-
schemaToUse,
|
|
192
|
-
toolInput,
|
|
193
|
-
{
|
|
194
|
-
toolName,
|
|
195
|
-
toolDescription: tool.description
|
|
196
|
-
},
|
|
197
|
-
missingFields
|
|
198
|
-
// Pass undefined for focused schemas, Set<string> for others
|
|
199
|
-
);
|
|
200
|
-
if (this.isZodObject(schemaToUse)) {
|
|
201
|
-
try {
|
|
202
|
-
const { jsonSchema, uiSchema } = this.formGenerator.generateJsonSchemaForm(
|
|
203
|
-
schemaToUse,
|
|
204
|
-
toolInput,
|
|
205
|
-
missingFields
|
|
206
|
-
);
|
|
207
|
-
formMessage.jsonSchema = jsonSchema;
|
|
208
|
-
formMessage.uiSchema = uiSchema;
|
|
209
|
-
} catch (error) {
|
|
210
|
-
this.formLogger.warn(
|
|
211
|
-
"Failed to generate JSON Schema for RJSF:",
|
|
212
|
-
error
|
|
213
|
-
);
|
|
58
|
+
aiProcessed[paramName] = out;
|
|
214
59
|
}
|
|
215
60
|
}
|
|
216
|
-
|
|
217
|
-
const formData = {
|
|
218
|
-
toolName,
|
|
219
|
-
originalInput: inputs,
|
|
220
|
-
originalToolInput: toolInput,
|
|
221
|
-
schema: schemaToUse,
|
|
222
|
-
toolRef: tool,
|
|
223
|
-
originalToolRef: tool.originalTool
|
|
224
|
-
};
|
|
225
|
-
this.pendingForms.set(formMessage.id, formData);
|
|
226
|
-
globalPendingForms.set(formMessage.id, formData);
|
|
227
|
-
this.formLogger.info(`✅ FORM INTERCEPT SUCCESS for ${toolName}`);
|
|
228
|
-
const formResult = {
|
|
229
|
-
requiresForm: true,
|
|
230
|
-
formMessage
|
|
231
|
-
};
|
|
232
|
-
return [
|
|
233
|
-
{
|
|
234
|
-
action,
|
|
235
|
-
observation: JSON.stringify(formResult)
|
|
236
|
-
}
|
|
237
|
-
];
|
|
61
|
+
working = aiProcessed;
|
|
238
62
|
} catch (error) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
`⚪ Passing through to normal tool execution for ${toolName}`
|
|
244
|
-
);
|
|
245
|
-
if (this.parameterPreprocessingCallback && toolInput) {
|
|
246
|
-
this.formLogger.info(
|
|
247
|
-
`🔄 Applying parameter preprocessing for ${toolName}`
|
|
248
|
-
);
|
|
249
|
-
try {
|
|
250
|
-
const preprocessedInput = await this.parameterPreprocessingCallback(
|
|
251
|
-
toolName,
|
|
252
|
-
toolInput
|
|
253
|
-
);
|
|
254
|
-
if (preprocessedInput && typeof preprocessedInput === "object" && "__requestForm" in preprocessedInput) {
|
|
255
|
-
const rf = preprocessedInput.__requestForm;
|
|
256
|
-
const formId = rf.id || `form_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
257
|
-
const formMessage = {
|
|
258
|
-
type: "form",
|
|
259
|
-
id: formId,
|
|
260
|
-
originalPrompt: "Parameter validation required",
|
|
261
|
-
toolName,
|
|
262
|
-
formConfig: {
|
|
263
|
-
title: rf.title || "Complete required parameters",
|
|
264
|
-
description: rf.description || "One or more parameters require confirmation. Please review and submit.",
|
|
265
|
-
submitLabel: rf.submitLabel || "Continue",
|
|
266
|
-
fields: (rf.fields || []).map((f) => {
|
|
267
|
-
const allowedTypes = [
|
|
268
|
-
"text",
|
|
269
|
-
"number",
|
|
270
|
-
"select",
|
|
271
|
-
"checkbox",
|
|
272
|
-
"textarea"
|
|
273
|
-
];
|
|
274
|
-
const resolvedType = allowedTypes.includes(
|
|
275
|
-
f.type
|
|
276
|
-
) ? f.type : "text";
|
|
277
|
-
return {
|
|
278
|
-
name: f.name,
|
|
279
|
-
label: f.label,
|
|
280
|
-
type: resolvedType,
|
|
281
|
-
required: f.required ?? true,
|
|
282
|
-
options: f.options
|
|
283
|
-
};
|
|
284
|
-
})
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
const resolvedSchema = isFormValidatable(tool) ? (() => {
|
|
288
|
-
try {
|
|
289
|
-
const s = tool.getFormSchema();
|
|
290
|
-
return s || tool.schema;
|
|
291
|
-
} catch {
|
|
292
|
-
return tool.schema;
|
|
293
|
-
}
|
|
294
|
-
})() : tool.schema;
|
|
295
|
-
this.pendingForms.set(formId, {
|
|
296
|
-
toolName,
|
|
297
|
-
originalInput: inputs,
|
|
298
|
-
originalToolInput: toolInput,
|
|
299
|
-
schema: resolvedSchema,
|
|
300
|
-
toolRef: tool,
|
|
301
|
-
originalToolRef: tool.originalTool
|
|
302
|
-
});
|
|
303
|
-
globalPendingForms.set(formId, {
|
|
63
|
+
const message = error instanceof Error ? error.message : "unknown";
|
|
64
|
+
this.logger.warn(
|
|
65
|
+
"AI phase failed; continuing with deterministic pass",
|
|
66
|
+
{
|
|
304
67
|
toolName,
|
|
305
|
-
|
|
306
|
-
originalToolInput: toolInput,
|
|
307
|
-
schema: resolvedSchema
|
|
308
|
-
});
|
|
309
|
-
return [
|
|
310
|
-
{
|
|
311
|
-
action,
|
|
312
|
-
observation: JSON.stringify({ requiresForm: true, formMessage })
|
|
313
|
-
}
|
|
314
|
-
];
|
|
315
|
-
}
|
|
316
|
-
if (JSON.stringify(preprocessedInput) !== JSON.stringify(toolInput)) {
|
|
317
|
-
this.formLogger.info(`📝 Parameters preprocessed for ${toolName}:`, {
|
|
318
|
-
original: Object.keys(toolInput),
|
|
319
|
-
preprocessed: Object.keys(preprocessedInput),
|
|
320
|
-
hasChanges: true
|
|
321
|
-
});
|
|
322
|
-
try {
|
|
323
|
-
action.toolInput = preprocessedInput;
|
|
324
|
-
} catch {
|
|
68
|
+
error: message
|
|
325
69
|
}
|
|
326
|
-
} else {
|
|
327
|
-
this.formLogger.debug(`No parameter changes needed for ${toolName}`);
|
|
328
|
-
}
|
|
329
|
-
} catch (preprocessError) {
|
|
330
|
-
this.formLogger.warn(
|
|
331
|
-
`Parameter preprocessing failed for ${toolName}, using original parameters:`,
|
|
332
|
-
preprocessError
|
|
333
70
|
);
|
|
334
71
|
}
|
|
335
72
|
}
|
|
336
|
-
return super._takeNextStep(
|
|
337
|
-
nameToolMap,
|
|
338
|
-
inputs,
|
|
339
|
-
intermediateSteps,
|
|
340
|
-
runManager,
|
|
341
|
-
config
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Helper to determine if a field is required in the schema
|
|
346
|
-
*/
|
|
347
|
-
isFieldRequired(schema, fieldPath) {
|
|
348
|
-
if (!schema || !fieldPath) {
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
try {
|
|
352
|
-
const obj = schema;
|
|
353
|
-
const def = obj._def;
|
|
354
|
-
if (!def || def.typeName !== "ZodObject") {
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
const rawShape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
358
|
-
if (!rawShape || typeof rawShape !== "object") {
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
const shape = rawShape;
|
|
362
|
-
const fieldSchema = shape[fieldPath];
|
|
363
|
-
if (!fieldSchema) {
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
const unwrapOptional = (s) => {
|
|
367
|
-
const inner = s._def;
|
|
368
|
-
if (inner && inner.typeName === "ZodOptional" && inner.innerType) {
|
|
369
|
-
return inner.innerType;
|
|
370
|
-
}
|
|
371
|
-
return s;
|
|
372
|
-
};
|
|
373
|
-
const unwrapped = unwrapOptional(fieldSchema);
|
|
374
|
-
const fdef = unwrapped._def;
|
|
375
|
-
if (!fdef) {
|
|
376
|
-
return true;
|
|
377
|
-
}
|
|
378
|
-
if (fdef.typeName === "ZodOptional" || fdef.typeName === "ZodDefault") {
|
|
379
|
-
return false;
|
|
380
|
-
}
|
|
381
|
-
if (fdef.defaultValue !== void 0) {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
return true;
|
|
385
|
-
} catch (error) {
|
|
386
|
-
this.formLogger.debug(
|
|
387
|
-
`Could not determine if field ${fieldPath} is required:`,
|
|
388
|
-
error
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Override _call to intercept Zod validation errors at the execution level
|
|
395
|
-
*/
|
|
396
|
-
async _call(inputs) {
|
|
397
73
|
try {
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
toolRef: toolInstance,
|
|
420
|
-
originalToolRef: originalToolCandidate?.originalTool
|
|
421
|
-
};
|
|
422
|
-
this.pendingForms.set(parsed.formMessage.id, pf);
|
|
423
|
-
globalPendingForms.set(parsed.formMessage.id, pf);
|
|
424
|
-
return {
|
|
425
|
-
...result,
|
|
426
|
-
requiresForm: true,
|
|
427
|
-
formMessage: parsed.formMessage,
|
|
428
|
-
output: parsed.message || "Please complete the form to continue."
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
if (parsed.hashLinkBlock || parsed.success && parsed.inscription && parsed.hashLinkBlock) {
|
|
432
|
-
this.formLogger.info("Tool returned HashLink blocks", {
|
|
433
|
-
toolName: step.action?.tool,
|
|
434
|
-
hasHashLink: true,
|
|
435
|
-
blockId: parsed.hashLinkBlock?.blockId
|
|
436
|
-
});
|
|
437
|
-
const hashLinkResponse = this.processHashLinkResponse(parsed);
|
|
438
|
-
return {
|
|
439
|
-
...result,
|
|
440
|
-
hasHashLinkBlocks: true,
|
|
441
|
-
hashLinkBlock: hashLinkResponse.hashLinkBlock,
|
|
442
|
-
output: hashLinkResponse.message
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
} catch {
|
|
74
|
+
const processed = { ...working };
|
|
75
|
+
for (const [paramName, paramValue] of Object.entries(working)) {
|
|
76
|
+
if (typeof paramValue === "string") {
|
|
77
|
+
const converted = await this.convertParameterEntities(
|
|
78
|
+
paramValue,
|
|
79
|
+
entities,
|
|
80
|
+
preferences
|
|
81
|
+
);
|
|
82
|
+
processed[paramName] = converted;
|
|
83
|
+
} else if (Array.isArray(paramValue)) {
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const item of paramValue) {
|
|
86
|
+
if (typeof item === "string") {
|
|
87
|
+
const converted = await this.convertParameterEntities(
|
|
88
|
+
item,
|
|
89
|
+
entities,
|
|
90
|
+
preferences
|
|
91
|
+
);
|
|
92
|
+
out.push(converted);
|
|
93
|
+
} else {
|
|
94
|
+
out.push(item);
|
|
446
95
|
}
|
|
447
96
|
}
|
|
97
|
+
processed[paramName] = out;
|
|
448
98
|
}
|
|
449
99
|
}
|
|
450
|
-
|
|
451
|
-
} catch (
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
throw error;
|
|
100
|
+
working = processed;
|
|
101
|
+
} catch (e) {
|
|
102
|
+
this.logger.warn("Deterministic post-pass failed", {
|
|
103
|
+
toolName,
|
|
104
|
+
error: e instanceof Error ? e.message : "unknown"
|
|
105
|
+
});
|
|
457
106
|
}
|
|
107
|
+
return working;
|
|
458
108
|
}
|
|
459
109
|
/**
|
|
460
|
-
*
|
|
110
|
+
* Attach unified preprocessing callback directly to the agent.
|
|
461
111
|
*/
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
112
|
+
attachToAgent(agent, deps) {
|
|
113
|
+
const getSessionId = deps?.getSessionId ?? (() => null);
|
|
114
|
+
const getEntities = deps?.getEntities ?? (async () => []);
|
|
115
|
+
const entityResolver = deps?.entityResolver;
|
|
116
|
+
const maybe = agent;
|
|
117
|
+
const attach = (target) => {
|
|
118
|
+
const t = target;
|
|
119
|
+
if (typeof t.setParameterPreprocessingCallback === "function") {
|
|
120
|
+
t.setParameterPreprocessingCallback(
|
|
121
|
+
async (toolName, parameters) => {
|
|
122
|
+
const sessionId = getSessionId();
|
|
123
|
+
const entities = await getEntities(sessionId);
|
|
124
|
+
const opts = {};
|
|
125
|
+
if (entityResolver) {
|
|
126
|
+
opts.entityResolver = entityResolver;
|
|
127
|
+
}
|
|
128
|
+
if (sessionId) {
|
|
129
|
+
opts.sessionId = sessionId;
|
|
130
|
+
}
|
|
131
|
+
return this.preprocessParameters(toolName, parameters, entities, opts);
|
|
132
|
+
}
|
|
480
133
|
);
|
|
481
|
-
|
|
134
|
+
this.logger.info("Parameter preprocessing callback attached");
|
|
135
|
+
return true;
|
|
482
136
|
}
|
|
483
|
-
|
|
484
|
-
}
|
|
485
|
-
this.formLogger.info("Generating form for tool:", {
|
|
486
|
-
toolName: toolInfo.toolName,
|
|
487
|
-
hasSchema: !!toolInfo.schema
|
|
488
|
-
});
|
|
489
|
-
const formMessage = this.formGenerator.generateFormFromError(
|
|
490
|
-
error,
|
|
491
|
-
toolInfo.schema,
|
|
492
|
-
toolInfo.toolName,
|
|
493
|
-
inputs.input || ""
|
|
494
|
-
);
|
|
495
|
-
this.pendingForms.set(formMessage.id, {
|
|
496
|
-
toolName: toolInfo.toolName,
|
|
497
|
-
originalInput: inputs,
|
|
498
|
-
schema: toolInfo.schema
|
|
499
|
-
});
|
|
500
|
-
globalPendingForms.set(formMessage.id, {
|
|
501
|
-
toolName: toolInfo.toolName,
|
|
502
|
-
originalInput: inputs,
|
|
503
|
-
schema: toolInfo.schema
|
|
504
|
-
});
|
|
505
|
-
return {
|
|
506
|
-
output: this.formatFormResponse(formMessage),
|
|
507
|
-
formMessage,
|
|
508
|
-
requiresForm: true,
|
|
509
|
-
intermediateSteps: intermediateSteps || []
|
|
137
|
+
return false;
|
|
510
138
|
};
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
return new Map(this.pendingForms);
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Restore pending forms from a previous executor instance
|
|
520
|
-
*/
|
|
521
|
-
restorePendingForms(forms) {
|
|
522
|
-
for (const [formId, formData] of forms) {
|
|
523
|
-
this.pendingForms.set(formId, formData);
|
|
139
|
+
if (!attach(agent) && typeof maybe.getAgent === "function") {
|
|
140
|
+
const underlying = maybe.getAgent();
|
|
141
|
+
if (underlying) {
|
|
142
|
+
void attach(underlying);
|
|
143
|
+
}
|
|
524
144
|
}
|
|
525
145
|
}
|
|
526
146
|
/**
|
|
527
|
-
*
|
|
147
|
+
* Preprocess tool parameters by applying format conversions based on tool's entity resolution preferences
|
|
528
148
|
*/
|
|
529
|
-
async
|
|
530
|
-
this.formLogger.info(
|
|
531
|
-
"🚀 FormAwareAgentExecutor.processFormSubmission called!",
|
|
532
|
-
{
|
|
533
|
-
submissionFormId: submission.formId,
|
|
534
|
-
submissionToolName: submission.toolName
|
|
535
|
-
}
|
|
536
|
-
);
|
|
537
|
-
if (!submission) {
|
|
538
|
-
throw new Error("Form submission is null or undefined");
|
|
539
|
-
}
|
|
540
|
-
if (!submission.formId) {
|
|
541
|
-
throw new Error("Form submission missing formId");
|
|
542
|
-
}
|
|
543
|
-
if (!submission.parameters || submission.parameters === null || typeof submission.parameters !== "object" || Array.isArray(submission.parameters)) {
|
|
544
|
-
throw new Error(
|
|
545
|
-
`Form submission parameters are invalid: ${typeof submission.parameters}, isNull: ${submission.parameters === null}, isArray: ${Array.isArray(
|
|
546
|
-
submission.parameters
|
|
547
|
-
)}, parameters: ${JSON.stringify(submission.parameters)}`
|
|
548
|
-
);
|
|
549
|
-
}
|
|
550
|
-
this.formLogger.info("Processing form submission:", {
|
|
551
|
-
formId: submission.formId,
|
|
552
|
-
toolName: submission.toolName,
|
|
553
|
-
parameterKeys: Object.keys(submission.parameters),
|
|
554
|
-
parametersType: typeof submission.parameters,
|
|
555
|
-
parametersIsNull: submission.parameters === null,
|
|
556
|
-
parametersIsUndefined: submission.parameters === void 0,
|
|
557
|
-
hasContext: !!submission.context
|
|
558
|
-
});
|
|
559
|
-
let pendingForm = this.pendingForms.get(submission.formId);
|
|
560
|
-
if (!pendingForm) {
|
|
561
|
-
pendingForm = globalPendingForms.get(submission.formId);
|
|
562
|
-
if (!pendingForm) {
|
|
563
|
-
throw new Error(`No pending form found for ID: ${submission.formId}`);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
this.pendingForms.delete(submission.formId);
|
|
567
|
-
globalPendingForms.delete(submission.formId);
|
|
568
|
-
const tool = pendingForm.toolRef || this.tools.find((t) => t.name === pendingForm.toolName);
|
|
569
|
-
if (!tool) {
|
|
570
|
-
throw new Error(
|
|
571
|
-
`Tool not found for form submission: ${pendingForm.toolName}`
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
let baseToolInput = {};
|
|
575
|
-
try {
|
|
576
|
-
if (pendingForm.originalToolInput && typeof pendingForm.originalToolInput === "object") {
|
|
577
|
-
baseToolInput = {
|
|
578
|
-
...pendingForm.originalToolInput
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
} catch (error) {
|
|
582
|
-
this.formLogger.warn(
|
|
583
|
-
"Failed to extract base tool input, using empty object:",
|
|
584
|
-
error
|
|
585
|
-
);
|
|
586
|
-
baseToolInput = {};
|
|
587
|
-
}
|
|
588
|
-
let submissionData = {};
|
|
589
|
-
try {
|
|
590
|
-
if (submission.parameters && typeof submission.parameters === "object") {
|
|
591
|
-
submissionData = {
|
|
592
|
-
...submission.parameters
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
} catch (error) {
|
|
596
|
-
this.formLogger.warn(
|
|
597
|
-
"Failed to extract submission parameters, using empty object:",
|
|
598
|
-
error
|
|
599
|
-
);
|
|
600
|
-
submissionData = {};
|
|
601
|
-
}
|
|
602
|
-
const mergedToolInput = {};
|
|
603
|
-
try {
|
|
604
|
-
Object.keys(baseToolInput).forEach((key) => {
|
|
605
|
-
const value = baseToolInput[key];
|
|
606
|
-
if (value !== void 0 && value !== null) {
|
|
607
|
-
mergedToolInput[key] = value;
|
|
608
|
-
}
|
|
609
|
-
});
|
|
610
|
-
Object.keys(submissionData).forEach((key) => {
|
|
611
|
-
const value = submissionData[key];
|
|
612
|
-
if (value !== void 0 && value !== null) {
|
|
613
|
-
mergedToolInput[key] = value;
|
|
614
|
-
}
|
|
615
|
-
});
|
|
616
|
-
mergedToolInput.renderForm = false;
|
|
617
|
-
mergedToolInput.__fromForm = true;
|
|
618
|
-
this.formLogger.info("Successfully merged tool input:", {
|
|
619
|
-
baseKeys: Object.keys(baseToolInput),
|
|
620
|
-
submissionKeys: Object.keys(submissionData),
|
|
621
|
-
mergedKeys: Object.keys(mergedToolInput)
|
|
622
|
-
});
|
|
623
|
-
} catch (error) {
|
|
624
|
-
this.formLogger.error("Failed to merge tool input data:", error);
|
|
625
|
-
throw new Error(
|
|
626
|
-
`Failed to merge tool input data: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
627
|
-
);
|
|
628
|
-
}
|
|
149
|
+
async preprocessToolParameters(toolName, parameters, entities, sessionId) {
|
|
629
150
|
try {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const otCall = ot;
|
|
637
|
-
if (ot && typeof otCall._call === "function") {
|
|
638
|
-
toolOutput = await otCall._call(mergedToolInput);
|
|
639
|
-
} else if (ot && typeof otCall.call === "function") {
|
|
640
|
-
toolOutput = await otCall.call(mergedToolInput);
|
|
641
|
-
} else {
|
|
642
|
-
const tcall = tool;
|
|
643
|
-
if (typeof tcall.call === "function") {
|
|
644
|
-
toolOutput = await tcall.call(mergedToolInput);
|
|
645
|
-
} else {
|
|
646
|
-
throw new Error(
|
|
647
|
-
"No callable tool implementation found for form submission"
|
|
648
|
-
);
|
|
151
|
+
if (!entities || entities.length === 0) {
|
|
152
|
+
this.logger.info(
|
|
153
|
+
"Tool parameter preprocessing skipped - no entities provided:",
|
|
154
|
+
{
|
|
155
|
+
toolName,
|
|
156
|
+
originalParams: Object.keys(parameters)
|
|
649
157
|
}
|
|
650
|
-
}
|
|
651
|
-
} else if (maybeWrapper.originalTool && typeof maybeWrapper.originalTool._call === "function") {
|
|
652
|
-
toolOutput = await maybeWrapper.originalTool._call(mergedToolInput);
|
|
653
|
-
} else if (maybeWrapper.originalTool && typeof maybeWrapper.originalTool.call === "function") {
|
|
654
|
-
toolOutput = await maybeWrapper.originalTool.call(mergedToolInput);
|
|
655
|
-
} else if (typeof tool.call === "function") {
|
|
656
|
-
toolOutput = await tool.call(mergedToolInput);
|
|
657
|
-
} else {
|
|
658
|
-
throw new Error(
|
|
659
|
-
"No callable tool implementation found for form submission"
|
|
660
158
|
);
|
|
159
|
+
return parameters;
|
|
661
160
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
161
|
+
const processedParameters = { ...parameters };
|
|
162
|
+
const preferences = void 0;
|
|
163
|
+
let hasChanges = false;
|
|
164
|
+
for (const [paramName, paramValue] of Object.entries(parameters)) {
|
|
165
|
+
if (typeof paramValue === "string") {
|
|
166
|
+
const convertedValue = await this.convertParameterEntities(
|
|
167
|
+
paramValue,
|
|
168
|
+
entities,
|
|
169
|
+
preferences
|
|
170
|
+
);
|
|
171
|
+
if (convertedValue !== paramValue) {
|
|
172
|
+
processedParameters[paramName] = convertedValue;
|
|
173
|
+
hasChanges = true;
|
|
174
|
+
this.logger.info("Parameter entity conversion applied:", {
|
|
175
|
+
toolName,
|
|
176
|
+
paramName,
|
|
177
|
+
original: paramValue,
|
|
178
|
+
converted: convertedValue
|
|
179
|
+
});
|
|
671
180
|
}
|
|
672
|
-
)
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
)
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
181
|
+
} else if (Array.isArray(paramValue)) {
|
|
182
|
+
const originalArray = paramValue;
|
|
183
|
+
const convertedArray = [];
|
|
184
|
+
let arrayChanged = false;
|
|
185
|
+
for (const item of originalArray) {
|
|
186
|
+
if (typeof item === "string") {
|
|
187
|
+
const convertedItem = await this.convertParameterEntities(
|
|
188
|
+
item,
|
|
189
|
+
entities,
|
|
190
|
+
preferences
|
|
191
|
+
);
|
|
192
|
+
convertedArray.push(convertedItem);
|
|
193
|
+
if (convertedItem !== item) {
|
|
194
|
+
arrayChanged = true;
|
|
195
|
+
this.logger.info("Parameter array item conversion applied:", {
|
|
196
|
+
toolName,
|
|
197
|
+
paramName,
|
|
198
|
+
original: item,
|
|
199
|
+
converted: convertedItem
|
|
200
|
+
});
|
|
688
201
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
responseMetadata = {
|
|
693
|
-
...responseMetadata,
|
|
694
|
-
hashLinkBlock: parsed.hashLinkBlock
|
|
695
|
-
};
|
|
202
|
+
} else {
|
|
203
|
+
convertedArray.push(item);
|
|
204
|
+
}
|
|
696
205
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
} catch (error) {
|
|
701
|
-
this.formLogger.warn(
|
|
702
|
-
"❌ METADATA EXTRACTION: Tool output is not JSON",
|
|
703
|
-
{
|
|
704
|
-
error: error instanceof Error ? error.message : "unknown error",
|
|
705
|
-
outputSample: typeof toolOutput === "string" ? toolOutput.substring(0, 200) : "not-string"
|
|
206
|
+
if (arrayChanged) {
|
|
207
|
+
processedParameters[paramName] = convertedArray;
|
|
208
|
+
hasChanges = true;
|
|
706
209
|
}
|
|
707
|
-
|
|
708
|
-
formattedOutput = ResponseFormatter.formatResponse(toolOutput);
|
|
210
|
+
}
|
|
709
211
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
toolName: pendingForm.toolName
|
|
718
|
-
};
|
|
212
|
+
this.logger.info("Tool parameter preprocessing completed:", {
|
|
213
|
+
toolName,
|
|
214
|
+
originalParams: Object.keys(parameters),
|
|
215
|
+
hasChanges,
|
|
216
|
+
sessionId
|
|
217
|
+
});
|
|
218
|
+
return processedParameters;
|
|
719
219
|
} catch (error) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
220
|
+
this.logger.warn("Tool parameter preprocessing failed:", {
|
|
221
|
+
toolName,
|
|
222
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
223
|
+
});
|
|
224
|
+
return parameters;
|
|
724
225
|
}
|
|
725
226
|
}
|
|
726
227
|
/**
|
|
727
|
-
*
|
|
228
|
+
* Convert entity references in a parameter value based on tool preferences
|
|
728
229
|
*/
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
this.formLogger.info(
|
|
737
|
-
"Found tool from intermediate steps:",
|
|
738
|
-
lastStep.action.tool
|
|
739
|
-
);
|
|
740
|
-
return {
|
|
741
|
-
toolName: lastStep.action.tool,
|
|
742
|
-
schema: tool.schema
|
|
743
|
-
};
|
|
744
|
-
}
|
|
745
|
-
}
|
|
230
|
+
async convertParameterEntities(parameterValue, entities, preferences) {
|
|
231
|
+
let convertedValue = parameterValue;
|
|
232
|
+
for (const entity of entities) {
|
|
233
|
+
const containsEntityId = convertedValue.includes(entity.entityId);
|
|
234
|
+
const containsEntityName = convertedValue.includes(entity.entityName);
|
|
235
|
+
if (!containsEntityId && !containsEntityName) {
|
|
236
|
+
continue;
|
|
746
237
|
}
|
|
747
|
-
|
|
748
|
-
if (
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if (
|
|
752
|
-
|
|
753
|
-
} else if (lastStep.action) {
|
|
754
|
-
action = lastStep.action;
|
|
755
|
-
} else {
|
|
756
|
-
action = lastStep;
|
|
238
|
+
let targetFormat = null;
|
|
239
|
+
if (entity.entityType === EntityFormat.TOPIC_ID) {
|
|
240
|
+
if (preferences?.inscription === "hrl" || preferences?.topic === "hrl") {
|
|
241
|
+
targetFormat = EntityFormat.HRL;
|
|
242
|
+
} else if (preferences?.inscription === "topicId" || preferences?.topic === "topicId") {
|
|
243
|
+
targetFormat = EntityFormat.TOPIC_ID;
|
|
757
244
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
toolName: action.tool,
|
|
764
|
-
schema: tool.schema
|
|
765
|
-
};
|
|
766
|
-
}
|
|
245
|
+
} else if (entity.entityType === EntityFormat.TOKEN_ID) {
|
|
246
|
+
if (preferences?.token === "tokenId") {
|
|
247
|
+
targetFormat = EntityFormat.TOKEN_ID;
|
|
248
|
+
} else if (preferences?.token === "symbol") {
|
|
249
|
+
targetFormat = EntityFormat.SYMBOL;
|
|
767
250
|
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
toolFromContext.toolName
|
|
774
|
-
);
|
|
775
|
-
return toolFromContext;
|
|
776
|
-
}
|
|
777
|
-
return null;
|
|
778
|
-
} catch (err) {
|
|
779
|
-
this.formLogger.error("Error extracting tool info:", err);
|
|
780
|
-
return null;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Attempts to find tool from execution context
|
|
785
|
-
*/
|
|
786
|
-
findToolFromContext(inputs) {
|
|
787
|
-
const inputText = inputs.input || "";
|
|
788
|
-
for (const tool of this.tools) {
|
|
789
|
-
const keywords = this.extractToolKeywords(tool.name);
|
|
790
|
-
if (keywords.some(
|
|
791
|
-
(keyword) => inputText.toLowerCase().includes(keyword.toLowerCase())
|
|
792
|
-
)) {
|
|
793
|
-
if ("schema" in tool) {
|
|
794
|
-
return {
|
|
795
|
-
toolName: tool.name,
|
|
796
|
-
schema: tool.schema
|
|
797
|
-
};
|
|
251
|
+
} else if (entity.entityType === EntityFormat.ACCOUNT_ID) {
|
|
252
|
+
if (preferences?.account === "accountId" || preferences?.supplyKey === "accountId" || preferences?.adminKey === "accountId") {
|
|
253
|
+
targetFormat = EntityFormat.ACCOUNT_ID;
|
|
254
|
+
} else if (preferences?.account === "alias") {
|
|
255
|
+
targetFormat = EntityFormat.ALIAS;
|
|
798
256
|
}
|
|
799
257
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
*/
|
|
806
|
-
detectToolFromErrorContext(error) {
|
|
807
|
-
const errorPaths = error.issues.map((issue) => issue.path.join("."));
|
|
808
|
-
for (const tool of this.tools) {
|
|
809
|
-
if ("schema" in tool) {
|
|
810
|
-
const toolSchema = tool.schema;
|
|
811
|
-
if (this.schemaMatchesErrorPaths(toolSchema, errorPaths)) {
|
|
812
|
-
this.formLogger.info(
|
|
813
|
-
"Detected tool from error path analysis:",
|
|
814
|
-
tool.name
|
|
815
|
-
);
|
|
816
|
-
return {
|
|
817
|
-
toolName: tool.name,
|
|
818
|
-
schema: toolSchema
|
|
258
|
+
if (targetFormat) {
|
|
259
|
+
try {
|
|
260
|
+
const context = {
|
|
261
|
+
networkType: this.networkType,
|
|
262
|
+
sessionId: "unknown"
|
|
819
263
|
};
|
|
264
|
+
if (preferences) {
|
|
265
|
+
context.toolPreferences = preferences;
|
|
266
|
+
}
|
|
267
|
+
const convertedEntityValue = await this.formatConverterRegistry.convertEntity(
|
|
268
|
+
entity.entityId,
|
|
269
|
+
targetFormat,
|
|
270
|
+
context
|
|
271
|
+
);
|
|
272
|
+
if (containsEntityId) {
|
|
273
|
+
convertedValue = convertedValue.replace(
|
|
274
|
+
new RegExp(`\\b${entity.entityId.replace(/\./g, "\\.")}\\b`, "g"),
|
|
275
|
+
convertedEntityValue
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
if (containsEntityName) {
|
|
279
|
+
convertedValue = convertedValue.replace(
|
|
280
|
+
new RegExp(
|
|
281
|
+
`\\b${entity.entityName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`,
|
|
282
|
+
"g"
|
|
283
|
+
),
|
|
284
|
+
convertedEntityValue
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
this.logger.info("Applied format conversion to parameter:", {
|
|
288
|
+
entityId: entity.entityId,
|
|
289
|
+
entityType: entity.entityType,
|
|
290
|
+
targetFormat,
|
|
291
|
+
convertedValue: convertedEntityValue,
|
|
292
|
+
parameterValue: convertedValue
|
|
293
|
+
});
|
|
294
|
+
} catch (error) {
|
|
295
|
+
this.logger.warn("Format conversion failed for parameter:", {
|
|
296
|
+
entityId: entity.entityId,
|
|
297
|
+
targetFormat,
|
|
298
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
299
|
+
});
|
|
820
300
|
}
|
|
821
301
|
}
|
|
822
302
|
}
|
|
823
|
-
return
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
* Checks if a schema structure matches error paths
|
|
827
|
-
*/
|
|
828
|
-
schemaMatchesErrorPaths(schema, errorPaths) {
|
|
829
|
-
const schemaRecord = schema;
|
|
830
|
-
if (!schemaRecord || !schemaRecord._def) return false;
|
|
831
|
-
try {
|
|
832
|
-
const def = schemaRecord._def;
|
|
833
|
-
if (def.typeName === "ZodObject") {
|
|
834
|
-
const shape = def.shape;
|
|
835
|
-
const schemaKeys = Object.keys(shape || {});
|
|
836
|
-
return errorPaths.some((path) => {
|
|
837
|
-
const topLevelKey = path.split(".")[0];
|
|
838
|
-
return schemaKeys.includes(topLevelKey);
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
} catch (err) {
|
|
842
|
-
this.formLogger.debug("Error analyzing schema structure:", err);
|
|
843
|
-
}
|
|
844
|
-
return false;
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Extracts keywords from tool name for matching
|
|
848
|
-
*/
|
|
849
|
-
extractToolKeywords(toolName) {
|
|
850
|
-
const words = toolName.replace(/([A-Z])/g, " $1").toLowerCase().split(/[\s_-]+/).filter((w) => w.length > 2);
|
|
851
|
-
return [...words, toolName.toLowerCase()];
|
|
852
|
-
}
|
|
853
|
-
/**
|
|
854
|
-
* Formats the form message for display
|
|
855
|
-
*/
|
|
856
|
-
formatFormResponse(formMessage) {
|
|
857
|
-
const fieldCount = formMessage.formConfig.fields.length;
|
|
858
|
-
const fieldList = formMessage.formConfig.fields.slice(0, 3).map((f) => `• ${f.label}`).join("\n");
|
|
859
|
-
return `I need some additional information to complete your request.
|
|
860
|
-
|
|
861
|
-
${formMessage.formConfig.description}
|
|
862
|
-
|
|
863
|
-
Required fields:
|
|
864
|
-
${fieldList}${fieldCount > 3 ? `
|
|
865
|
-
... and ${fieldCount - 3} more` : ""}
|
|
866
|
-
|
|
867
|
-
Please fill out the form below to continue.`;
|
|
868
|
-
}
|
|
869
|
-
/**
|
|
870
|
-
* Check if there are pending forms
|
|
871
|
-
*/
|
|
872
|
-
hasPendingForms() {
|
|
873
|
-
return this.pendingForms.size > 0;
|
|
874
|
-
}
|
|
875
|
-
/**
|
|
876
|
-
* Get information about pending forms
|
|
877
|
-
*/
|
|
878
|
-
getPendingFormsInfo() {
|
|
879
|
-
return Array.from(this.pendingForms.entries()).map(([formId, info]) => ({
|
|
880
|
-
formId,
|
|
881
|
-
toolName: info.toolName
|
|
882
|
-
}));
|
|
883
|
-
}
|
|
884
|
-
/**
|
|
885
|
-
* Processes HashLink block responses from tools
|
|
886
|
-
*/
|
|
887
|
-
processHashLinkResponse(toolResponse) {
|
|
888
|
-
try {
|
|
889
|
-
let hashLinkBlock;
|
|
890
|
-
if (toolResponse.hashLinkBlock) {
|
|
891
|
-
hashLinkBlock = toolResponse.hashLinkBlock;
|
|
892
|
-
} else if (toolResponse.success && toolResponse.inscription && toolResponse.hashLinkBlock) {
|
|
893
|
-
hashLinkBlock = toolResponse.hashLinkBlock;
|
|
894
|
-
}
|
|
895
|
-
if (!hashLinkBlock) {
|
|
896
|
-
throw new Error("HashLink block data not found in response");
|
|
897
|
-
}
|
|
898
|
-
if (!hashLinkBlock.blockId || !hashLinkBlock.hashLink || !hashLinkBlock.attributes) {
|
|
899
|
-
throw new Error(
|
|
900
|
-
"Invalid HashLink block structure - missing required fields"
|
|
901
|
-
);
|
|
902
|
-
}
|
|
903
|
-
let message = "Content processed successfully!";
|
|
904
|
-
if (toolResponse.success && toolResponse.inscription) {
|
|
905
|
-
const inscription = toolResponse.inscription;
|
|
906
|
-
const metadata = toolResponse.metadata || {};
|
|
907
|
-
message = `✅ ${inscription.standard} Hashinal inscription completed!
|
|
908
|
-
|
|
909
|
-
`;
|
|
910
|
-
if (metadata.name) {
|
|
911
|
-
message += `**${metadata.name}**
|
|
912
|
-
`;
|
|
913
|
-
}
|
|
914
|
-
if (metadata.description) {
|
|
915
|
-
message += `${metadata.description}
|
|
916
|
-
|
|
917
|
-
`;
|
|
918
|
-
}
|
|
919
|
-
message += `📍 **Topic ID:** ${inscription.topicId}
|
|
920
|
-
`;
|
|
921
|
-
message += `🔗 **HRL:** ${inscription.hrl}
|
|
922
|
-
`;
|
|
923
|
-
if (inscription.cdnUrl) {
|
|
924
|
-
message += `🌐 **CDN URL:** ${inscription.cdnUrl}
|
|
925
|
-
`;
|
|
926
|
-
}
|
|
927
|
-
if (metadata.creator) {
|
|
928
|
-
message += `👤 **Creator:** ${metadata.creator}
|
|
929
|
-
`;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
this.formLogger.info("Processed HashLink response", {
|
|
933
|
-
blockId: hashLinkBlock.blockId,
|
|
934
|
-
hashLink: hashLinkBlock.hashLink,
|
|
935
|
-
hasTemplate: !!hashLinkBlock.template,
|
|
936
|
-
attributeCount: Object.keys(hashLinkBlock.attributes || {}).length
|
|
937
|
-
});
|
|
938
|
-
return {
|
|
939
|
-
hasHashLinkBlocks: true,
|
|
940
|
-
hashLinkBlock,
|
|
941
|
-
message
|
|
942
|
-
};
|
|
943
|
-
} catch (error) {
|
|
944
|
-
this.formLogger.error("Error processing HashLink response:", error);
|
|
945
|
-
return {
|
|
946
|
-
hasHashLinkBlocks: false,
|
|
947
|
-
message: "Content processed, but interactive display is not available."
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
/**
|
|
952
|
-
* Get FormEngine statistics for debugging
|
|
953
|
-
*/
|
|
954
|
-
getFormEngineStatistics() {
|
|
955
|
-
return {
|
|
956
|
-
strategies: this.formEngine.getRegisteredStrategies(),
|
|
957
|
-
middleware: this.formEngine.getRegisteredMiddleware()
|
|
958
|
-
};
|
|
303
|
+
return convertedValue;
|
|
959
304
|
}
|
|
960
305
|
}
|
|
961
306
|
export {
|
|
962
|
-
|
|
307
|
+
ParameterService
|
|
963
308
|
};
|
|
964
309
|
//# sourceMappingURL=index29.js.map
|