@hashgraphonline/conversational-agent
Version:
Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera. https://hol.org
130 lines (119 loc) • 4.07 kB
JavaScript
import { StructuredTool } from "@langchain/core/tools";
import { z } from "zod";
import { Logger } from "@hashgraphonline/standards-sdk";
const logger = new Logger({ module: "EntityResolverTool" });
const ResolveEntitiesSchema = z.object({
message: z.string().describe("The message containing entity references to resolve"),
entities: z.array(z.object({
entityId: z.string(),
entityName: z.string(),
entityType: z.string()
})).describe("Available entities in memory")
});
const ExtractEntitiesSchema = z.object({
response: z.string().describe("Agent response text to extract entities from"),
userMessage: z.string().describe("Original user message for context")
});
class ResolveEntitiesTool extends StructuredTool {
constructor(llm) {
super();
this.name = "resolve_entities";
this.description = 'Resolves entity references like "the topic", "it", "that" to actual entity IDs';
this.schema = ResolveEntitiesSchema;
this.llm = llm;
}
async _call(input) {
const { message, entities } = input;
if (!entities || entities.length === 0) {
return message;
}
const byType = this.groupEntitiesByType(entities);
const context = this.buildEntityContext(byType);
const prompt = `Task: Replace entity references with IDs.
${context}
Message: "${message}"
Rules:
- "the topic" or "that topic" → replace with most recent topic ID
- "the token" or "that token" → replace with most recent token ID
- "it" or "that" after action verb → replace with most recent entity ID
- "airdrop X" without token ID → add most recent token ID as first parameter
- Token operations without explicit token → use most recent token ID
Examples:
- "submit on the topic" → "submit on 0.0.6543472"
- "airdrop the token" → "airdrop 0.0.123456"
- "airdrop 10 to 0.0.5842697" → "airdrop 0.0.123456 10 to 0.0.5842697"
- "mint 100" → "mint 0.0.123456 100"
Return ONLY the resolved message:`;
try {
const response = await this.llm.invoke(prompt);
return response.content.trim();
} catch (error) {
logger.error("ResolveEntitiesTool failed:", error);
return message;
}
}
groupEntitiesByType(entities) {
return entities.reduce((acc, entity) => {
if (!acc[entity.entityType]) {
acc[entity.entityType] = [];
}
acc[entity.entityType].push(entity);
return acc;
}, {});
}
buildEntityContext(groupedEntities) {
let context = "Available entities:\n";
for (const [type, list] of Object.entries(groupedEntities)) {
const recent = list[0];
context += `- Most recent ${type}: "${recent.entityName}" = ${recent.entityId}
`;
}
return context;
}
}
class ExtractEntitiesTool extends StructuredTool {
constructor(llm) {
super();
this.name = "extract_entities";
this.description = "Extracts newly created entities from agent responses";
this.schema = ExtractEntitiesSchema;
this.llm = llm;
}
async _call(input) {
const { response, userMessage } = input;
const prompt = `Extract ONLY newly created entities from this response.
User asked: "${userMessage.substring(0, 200)}"
Response: ${response.substring(0, 3e3)}
Look for:
- Success messages with new entity IDs
- Words like "created", "new", "successfully" followed by entity IDs
Return JSON array of created entities:
[{"id": "0.0.XXX", "name": "name", "type": "topic|token|account"}]
If none created, return: []
JSON:`;
try {
const llmResponse = await this.llm.invoke(prompt);
const content = llmResponse.content;
const match = content.match(/\[[\s\S]*?\]/);
if (match) {
return match[0];
}
return "[]";
} catch (error) {
logger.error("ExtractEntitiesTool failed:", error);
return "[]";
}
}
}
function createEntityTools(llm) {
return {
resolveEntities: new ResolveEntitiesTool(llm),
extractEntities: new ExtractEntitiesTool(llm)
};
}
export {
ExtractEntitiesTool,
ResolveEntitiesTool,
createEntityTools
};
//# sourceMappingURL=index35.js.map