@hashgraphonline/conversational-agent 0.0.3 → 0.1.1
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 +79 -0
- package/dist/cjs/agent-factory.d.ts +5 -0
- package/dist/cjs/base-agent.d.ts +95 -0
- package/dist/cjs/conversational-agent.d.ts +62 -5
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +8 -0
- package/dist/cjs/langchain-agent.d.ts +22 -0
- package/dist/cjs/mcp/MCPClientManager.d.ts +40 -0
- package/dist/cjs/mcp/adapters/langchain.d.ts +8 -0
- package/dist/cjs/mcp/helpers.d.ts +45 -0
- package/dist/cjs/mcp/types.d.ts +27 -0
- package/dist/cjs/plugins/hbar-transfer/AccountBuilder.d.ts +13 -0
- package/dist/cjs/plugins/hbar-transfer/HbarTransferPlugin.d.ts +15 -0
- package/dist/cjs/plugins/hbar-transfer/TransferHbarTool.d.ts +61 -0
- package/dist/cjs/plugins/hbar-transfer/index.d.ts +1 -0
- package/dist/cjs/plugins/hbar-transfer/types.d.ts +10 -0
- package/dist/cjs/plugins/index.d.ts +1 -0
- package/dist/cjs/providers.d.ts +48 -0
- package/dist/esm/index.js +18 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index10.js +22 -0
- package/dist/esm/index10.js.map +1 -0
- package/dist/esm/index11.js +104 -0
- package/dist/esm/index11.js.map +1 -0
- package/dist/esm/index12.js +36 -0
- package/dist/esm/index12.js.map +1 -0
- package/dist/esm/index13.js +16 -0
- package/dist/esm/index13.js.map +1 -0
- package/dist/esm/index14.js +127 -0
- package/dist/esm/index14.js.map +1 -0
- package/dist/esm/index15.js +132 -0
- package/dist/esm/index15.js.map +1 -0
- package/dist/esm/index16.js +95 -0
- package/dist/esm/index16.js.map +1 -0
- package/dist/esm/index5.js +42 -202
- package/dist/esm/index5.js.map +1 -1
- package/dist/esm/index6.js +295 -13
- package/dist/esm/index6.js.map +1 -1
- package/dist/esm/index7.js +87 -0
- package/dist/esm/index7.js.map +1 -0
- package/dist/esm/index8.js +255 -0
- package/dist/esm/index8.js.map +1 -0
- package/dist/esm/index9.js +18 -0
- package/dist/esm/index9.js.map +1 -0
- package/dist/types/agent-factory.d.ts +5 -0
- package/dist/types/base-agent.d.ts +95 -0
- package/dist/types/conversational-agent.d.ts +62 -5
- package/dist/types/index.d.ts +8 -0
- package/dist/types/langchain-agent.d.ts +22 -0
- package/dist/types/mcp/MCPClientManager.d.ts +40 -0
- package/dist/types/mcp/adapters/langchain.d.ts +8 -0
- package/dist/types/mcp/helpers.d.ts +45 -0
- package/dist/types/mcp/types.d.ts +27 -0
- package/dist/types/plugins/hbar-transfer/AccountBuilder.d.ts +13 -0
- package/dist/types/plugins/hbar-transfer/HbarTransferPlugin.d.ts +15 -0
- package/dist/types/plugins/hbar-transfer/TransferHbarTool.d.ts +61 -0
- package/dist/types/plugins/hbar-transfer/index.d.ts +1 -0
- package/dist/types/plugins/hbar-transfer/types.d.ts +10 -0
- package/dist/types/plugins/index.d.ts +1 -0
- package/dist/types/providers.d.ts +48 -0
- package/package.json +12 -6
- package/src/agent-factory.ts +21 -0
- package/src/base-agent.ts +222 -0
- package/src/conversational-agent.ts +204 -102
- package/src/index.ts +24 -0
- package/src/langchain-agent.ts +333 -0
- package/src/mcp/MCPClientManager.ts +148 -0
- package/src/mcp/adapters/langchain.ts +185 -0
- package/src/mcp/helpers.ts +122 -0
- package/src/mcp/types.ts +29 -0
- package/src/plugins/hbar-transfer/AccountBuilder.ts +154 -0
- package/src/plugins/hbar-transfer/HbarTransferPlugin.ts +66 -0
- package/src/plugins/hbar-transfer/TransferHbarTool.ts +49 -0
- package/src/plugins/hbar-transfer/index.ts +1 -0
- package/src/plugins/hbar-transfer/types.ts +11 -0
- package/src/plugins/index.ts +2 -1
- package/src/providers.ts +82 -0
package/dist/esm/index6.js
CHANGED
|
@@ -1,16 +1,298 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { ServerSigner, getAllHederaCorePlugins } from "hedera-agent-kit";
|
|
2
|
+
import { Logger, HederaMirrorNode } from "@hashgraphonline/standards-sdk";
|
|
3
|
+
import { createAgent } from "./index9.js";
|
|
4
|
+
import { LangChainProvider } from "./index10.js";
|
|
5
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
6
|
+
import { HumanMessage, AIMessage } from "@langchain/core/messages";
|
|
7
|
+
import { HCS10Plugin } from "./index2.js";
|
|
8
|
+
import { HCS2Plugin } from "./index3.js";
|
|
9
|
+
import { InscribePlugin } from "./index4.js";
|
|
10
|
+
import { HbarTransferPlugin } from "./index5.js";
|
|
11
|
+
import { OpenConvaiState } from "@hashgraphonline/standards-agent-kit";
|
|
12
|
+
import { PrivateKey } from "@hashgraph/sdk";
|
|
13
|
+
import { getSystemMessage } from "./index13.js";
|
|
14
|
+
const DEFAULT_MODEL_NAME = "gpt-4o";
|
|
15
|
+
const DEFAULT_TEMPERATURE = 0.1;
|
|
16
|
+
const DEFAULT_NETWORK = "testnet";
|
|
17
|
+
const DEFAULT_OPERATIONAL_MODE = "autonomous";
|
|
18
|
+
class ConversationalAgent {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.stateManager = options.stateManager || new OpenConvaiState();
|
|
22
|
+
this.hcs10Plugin = new HCS10Plugin();
|
|
23
|
+
this.hcs2Plugin = new HCS2Plugin();
|
|
24
|
+
this.inscribePlugin = new InscribePlugin();
|
|
25
|
+
this.hbarTransferPlugin = new HbarTransferPlugin();
|
|
26
|
+
this.logger = new Logger({
|
|
27
|
+
module: "ConversationalAgent",
|
|
28
|
+
silent: options.disableLogging || false
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the conversational agent with Hedera network connection and AI configuration
|
|
33
|
+
* @throws {Error} If account ID or private key is missing
|
|
34
|
+
* @throws {Error} If initialization fails
|
|
35
|
+
*/
|
|
36
|
+
async initialize() {
|
|
37
|
+
const {
|
|
38
|
+
accountId,
|
|
39
|
+
privateKey,
|
|
40
|
+
network = DEFAULT_NETWORK,
|
|
41
|
+
openAIApiKey,
|
|
42
|
+
openAIModelName = DEFAULT_MODEL_NAME,
|
|
43
|
+
verbose = false,
|
|
44
|
+
operationalMode = DEFAULT_OPERATIONAL_MODE,
|
|
45
|
+
userAccountId,
|
|
46
|
+
customSystemMessagePreamble,
|
|
47
|
+
customSystemMessagePostamble,
|
|
48
|
+
additionalPlugins = [],
|
|
49
|
+
mirrorNodeConfig,
|
|
50
|
+
disableLogging,
|
|
51
|
+
scheduleUserTransactionsInBytesMode
|
|
52
|
+
} = this.options;
|
|
53
|
+
if (!accountId || !privateKey) {
|
|
54
|
+
throw new Error("Account ID and private key are required");
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const privateKeyInstance = await this.detectPrivateKeyType(
|
|
58
|
+
accountId,
|
|
59
|
+
privateKey,
|
|
60
|
+
network
|
|
61
|
+
);
|
|
62
|
+
const serverSigner = new ServerSigner(
|
|
63
|
+
accountId,
|
|
64
|
+
privateKeyInstance,
|
|
65
|
+
network
|
|
66
|
+
);
|
|
67
|
+
const standardPlugins = [
|
|
68
|
+
this.hcs10Plugin,
|
|
69
|
+
this.hcs2Plugin,
|
|
70
|
+
this.inscribePlugin,
|
|
71
|
+
this.hbarTransferPlugin
|
|
72
|
+
];
|
|
73
|
+
const corePlugins = getAllHederaCorePlugins();
|
|
74
|
+
let allPlugins;
|
|
75
|
+
if (this.options.enabledPlugins) {
|
|
76
|
+
const enabledSet = new Set(this.options.enabledPlugins);
|
|
77
|
+
const filteredPlugins = [...standardPlugins, ...corePlugins].filter(
|
|
78
|
+
(plugin) => enabledSet.has(plugin.id)
|
|
79
|
+
);
|
|
80
|
+
allPlugins = [...filteredPlugins, ...additionalPlugins];
|
|
81
|
+
} else {
|
|
82
|
+
allPlugins = [...standardPlugins, ...corePlugins, ...additionalPlugins];
|
|
83
|
+
}
|
|
84
|
+
const llm = new ChatOpenAI({
|
|
85
|
+
apiKey: openAIApiKey,
|
|
86
|
+
modelName: openAIModelName,
|
|
87
|
+
temperature: DEFAULT_TEMPERATURE
|
|
88
|
+
});
|
|
89
|
+
this.agent = createAgent({
|
|
90
|
+
framework: "langchain",
|
|
91
|
+
signer: serverSigner,
|
|
92
|
+
execution: {
|
|
93
|
+
mode: operationalMode === "autonomous" ? "direct" : "bytes",
|
|
94
|
+
operationalMode,
|
|
95
|
+
...userAccountId && { userAccountId },
|
|
96
|
+
...scheduleUserTransactionsInBytesMode !== void 0 && {
|
|
97
|
+
scheduleUserTransactions: scheduleUserTransactionsInBytesMode
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
ai: {
|
|
101
|
+
provider: new LangChainProvider(llm),
|
|
102
|
+
temperature: DEFAULT_TEMPERATURE
|
|
103
|
+
},
|
|
104
|
+
filtering: {
|
|
105
|
+
toolPredicate: (tool) => {
|
|
106
|
+
if (tool.name === "hedera-account-transfer-hbar") return false;
|
|
107
|
+
if (this.options.toolFilter && !this.options.toolFilter(tool)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
messaging: {
|
|
114
|
+
systemPreamble: customSystemMessagePreamble || getSystemMessage(accountId),
|
|
115
|
+
...customSystemMessagePostamble && { systemPostamble: customSystemMessagePostamble },
|
|
116
|
+
conciseMode: true
|
|
117
|
+
},
|
|
118
|
+
extensions: {
|
|
119
|
+
plugins: allPlugins,
|
|
120
|
+
...mirrorNodeConfig && {
|
|
121
|
+
mirrorConfig: mirrorNodeConfig
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
...this.options.mcpServers && {
|
|
125
|
+
mcp: {
|
|
126
|
+
servers: this.options.mcpServers,
|
|
127
|
+
autoConnect: true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
debug: {
|
|
131
|
+
verbose,
|
|
132
|
+
silent: disableLogging ?? false
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const hcs10 = allPlugins.find((p) => p.id === "hcs-10");
|
|
136
|
+
if (hcs10) {
|
|
137
|
+
hcs10.appConfig = {
|
|
138
|
+
stateManager: this.stateManager
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
await this.agent.boot();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
this.logger.error("Failed to initialize ConversationalAgent:", error);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the HCS-10 plugin instance
|
|
149
|
+
* @returns {HCS10Plugin} The HCS-10 plugin instance
|
|
150
|
+
*/
|
|
151
|
+
getPlugin() {
|
|
152
|
+
return this.hcs10Plugin;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the state manager instance
|
|
156
|
+
* @returns {IStateManager} The state manager instance
|
|
157
|
+
*/
|
|
158
|
+
getStateManager() {
|
|
159
|
+
return this.stateManager;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the underlying agent instance
|
|
163
|
+
* @returns {ReturnType<typeof createAgent>} The agent instance
|
|
164
|
+
* @throws {Error} If agent is not initialized
|
|
165
|
+
*/
|
|
166
|
+
getAgent() {
|
|
167
|
+
if (!this.agent) {
|
|
168
|
+
throw new Error("Agent not initialized. Call initialize() first.");
|
|
169
|
+
}
|
|
170
|
+
return this.agent;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get the conversational agent instance (alias for getAgent)
|
|
174
|
+
* @returns {ReturnType<typeof createAgent>} The agent instance
|
|
175
|
+
* @throws {Error} If agent is not initialized
|
|
176
|
+
*/
|
|
177
|
+
getConversationalAgent() {
|
|
178
|
+
return this.getAgent();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Process a message through the conversational agent
|
|
182
|
+
* @param {string} message - The message to process
|
|
183
|
+
* @param {Array<{type: 'human' | 'ai'; content: string}>} chatHistory - Previous chat history
|
|
184
|
+
* @returns {Promise<ChatResponse>} The agent's response
|
|
185
|
+
* @throws {Error} If agent is not initialized
|
|
186
|
+
*/
|
|
187
|
+
async processMessage(message, chatHistory = []) {
|
|
188
|
+
if (!this.agent) {
|
|
189
|
+
throw new Error("Agent not initialized. Call initialize() first.");
|
|
190
|
+
}
|
|
191
|
+
const messages = chatHistory.map(
|
|
192
|
+
(msg) => msg.type === "human" ? new HumanMessage(msg.content) : new AIMessage(msg.content)
|
|
193
|
+
);
|
|
194
|
+
const context = {
|
|
195
|
+
messages
|
|
196
|
+
};
|
|
197
|
+
return this.agent.chat(message, context);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Create a ConversationalAgent with specific plugins enabled
|
|
201
|
+
*/
|
|
202
|
+
static withPlugins(options, plugins) {
|
|
203
|
+
return new ConversationalAgent({
|
|
204
|
+
...options,
|
|
205
|
+
enabledPlugins: plugins
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Create a ConversationalAgent with only HTS (Hedera Token Service) tools enabled
|
|
210
|
+
*/
|
|
211
|
+
static withHTS(options) {
|
|
212
|
+
return this.withPlugins(options, ["hts-token"]);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Create a ConversationalAgent with only HCS-2 tools enabled
|
|
216
|
+
*/
|
|
217
|
+
static withHCS2(options) {
|
|
218
|
+
return this.withPlugins(options, ["hcs-2"]);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Create a ConversationalAgent with only HCS-10 tools enabled
|
|
222
|
+
*/
|
|
223
|
+
static withHCS10(options) {
|
|
224
|
+
return this.withPlugins(options, ["hcs-10"]);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Create a ConversationalAgent with only inscription tools enabled
|
|
228
|
+
*/
|
|
229
|
+
static withInscribe(options) {
|
|
230
|
+
return this.withPlugins(options, ["inscribe"]);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a ConversationalAgent with only account management tools enabled
|
|
234
|
+
*/
|
|
235
|
+
static withAccount(options) {
|
|
236
|
+
return this.withPlugins(options, ["account"]);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create a ConversationalAgent with only file service tools enabled
|
|
240
|
+
*/
|
|
241
|
+
static withFileService(options) {
|
|
242
|
+
return this.withPlugins(options, ["file-service"]);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create a ConversationalAgent with only consensus service tools enabled
|
|
246
|
+
*/
|
|
247
|
+
static withConsensusService(options) {
|
|
248
|
+
return this.withPlugins(options, ["consensus-service"]);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create a ConversationalAgent with only smart contract tools enabled
|
|
252
|
+
*/
|
|
253
|
+
static withSmartContract(options) {
|
|
254
|
+
return this.withPlugins(options, ["smart-contract"]);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Create a ConversationalAgent with all HCS standards plugins
|
|
258
|
+
*/
|
|
259
|
+
static withAllStandards(options) {
|
|
260
|
+
return this.withPlugins(options, ["hcs-10", "hcs-2", "inscribe"]);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Create a ConversationalAgent with minimal Hedera tools (no HCS standards)
|
|
264
|
+
*/
|
|
265
|
+
static minimal(options) {
|
|
266
|
+
return this.withPlugins(options, []);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create a ConversationalAgent with MCP servers configured
|
|
270
|
+
*/
|
|
271
|
+
static withMCP(options, mcpServers) {
|
|
272
|
+
return new ConversationalAgent({
|
|
273
|
+
...options,
|
|
274
|
+
mcpServers
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Detect the private key type by querying the account info from mirror node
|
|
279
|
+
* @param {string} accountId - The Hedera account ID
|
|
280
|
+
* @param {string} privateKey - The private key string
|
|
281
|
+
* @param {NetworkType} network - The Hedera network
|
|
282
|
+
* @returns {Promise<PrivateKey>} The appropriate PrivateKey instance
|
|
283
|
+
*/
|
|
284
|
+
async detectPrivateKeyType(accountId, privateKey, network) {
|
|
285
|
+
const mirrorNode = new HederaMirrorNode(network);
|
|
286
|
+
const accountInfo = await mirrorNode.requestAccount(accountId);
|
|
287
|
+
const keyType = accountInfo?.key?._type || "";
|
|
288
|
+
if (keyType?.toLowerCase()?.includes("ecdsa")) {
|
|
289
|
+
return PrivateKey.fromStringECDSA(privateKey);
|
|
290
|
+
} else {
|
|
291
|
+
return PrivateKey.fromStringED25519(privateKey);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
13
295
|
export {
|
|
14
|
-
|
|
296
|
+
ConversationalAgent
|
|
15
297
|
};
|
|
16
298
|
//# sourceMappingURL=index6.js.map
|
package/dist/esm/index6.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index6.js","sources":["../../src/config/system-message.ts"],"sourcesContent":["export const getSystemMessage = (accountId: string): string => `You are a helpful assistant managing Hashgraph Online HCS-10 connections, messages, HCS-2 registries, and content inscription.\n\nYou have access to tools for:\n- HCS-10: registering agents, finding registered agents, initiating connections, listing active connections, sending messages over connections, and checking for new messages\n- HCS-2: creating registries, registering entries, updating entries, deleting entries, migrating registries, and querying registry contents\n- Inscription: inscribing content from URLs, files, or buffers, creating Hashinal NFTs, and retrieving inscriptions\n\n*** IMPORTANT CONTEXT ***\nYou are currently operating as agent: ${accountId} on the Hashgraph Online network\nWhen users ask about \"my profile\", \"my account\", \"my connections\", etc., use this account ID: ${accountId}\n\nRemember the connection numbers when listing connections, as users might refer to them.`"],"names":[],"mappings":"AAAO,MAAM,mBAAmB,CAAC,cAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAQvB,SAAS;AAAA,gGAC+C,SAAS;AAAA;AAAA;"}
|
|
1
|
+
{"version":3,"file":"index6.js","sources":["../../src/conversational-agent.ts"],"sourcesContent":["import {\n ServerSigner,\n getAllHederaCorePlugins,\n BasePlugin,\n} from 'hedera-agent-kit';\nimport {\n HederaMirrorNode,\n Logger,\n type NetworkType,\n} from '@hashgraphonline/standards-sdk';\nimport { createAgent } from './agent-factory';\nimport { LangChainProvider } from './providers';\nimport type { ChatResponse, ConversationContext } from './base-agent';\nimport { ChatOpenAI } from '@langchain/openai';\nimport { HumanMessage, AIMessage } from '@langchain/core/messages';\nimport type { AgentOperationalMode, MirrorNodeConfig } from 'hedera-agent-kit';\nimport { HCS10Plugin } from './plugins/hcs-10/HCS10Plugin';\nimport { HCS2Plugin } from './plugins/hcs-2/HCS2Plugin';\nimport { InscribePlugin } from './plugins/inscribe/InscribePlugin';\nimport { HbarTransferPlugin } from './plugins/hbar-transfer/HbarTransferPlugin';\nimport { OpenConvaiState } from '@hashgraphonline/standards-agent-kit';\nimport type { IStateManager } from '@hashgraphonline/standards-agent-kit';\nimport { PrivateKey } from '@hashgraph/sdk';\nimport { getSystemMessage } from './config/system-message';\nimport type { MCPServerConfig } from './mcp/types';\n\nconst DEFAULT_MODEL_NAME = 'gpt-4o';\nconst DEFAULT_TEMPERATURE = 0.1;\nconst DEFAULT_NETWORK = 'testnet';\nconst DEFAULT_OPERATIONAL_MODE: AgentOperationalMode = 'autonomous';\n\nexport interface ConversationalAgentOptions {\n accountId: string;\n privateKey: string;\n network?: NetworkType;\n openAIApiKey: string;\n openAIModelName?: string;\n verbose?: boolean;\n operationalMode?: AgentOperationalMode;\n userAccountId?: string;\n customSystemMessagePreamble?: string;\n customSystemMessagePostamble?: string;\n additionalPlugins?: BasePlugin[];\n stateManager?: IStateManager;\n scheduleUserTransactionsInBytesMode?: boolean;\n mirrorNodeConfig?: MirrorNodeConfig;\n disableLogging?: boolean;\n enabledPlugins?: string[];\n toolFilter?: (tool: { name: string; namespace?: string }) => boolean;\n mcpServers?: MCPServerConfig[];\n}\n\n/**\n * The ConversationalAgent class is an optional wrapper around the HederaConversationalAgent class,\n * which includes the OpenConvAIPlugin and the OpenConvaiState by default.\n * If you want to use a different plugin or state manager, you can pass them in the options.\n * This class is not required and the plugin can be used directly with the HederaConversationalAgent class.\n *\n * @param options - The options for the ConversationalAgent.\n * @returns A new instance of the ConversationalAgent class.\n */\nexport class ConversationalAgent {\n private agent?: ReturnType<typeof createAgent>;\n public hcs10Plugin: HCS10Plugin;\n public hcs2Plugin: HCS2Plugin;\n public inscribePlugin: InscribePlugin;\n public hbarTransferPlugin: HbarTransferPlugin;\n public stateManager: IStateManager;\n private options: ConversationalAgentOptions;\n private logger: Logger;\n\n constructor(options: ConversationalAgentOptions) {\n this.options = options;\n this.stateManager = options.stateManager || new OpenConvaiState();\n this.hcs10Plugin = new HCS10Plugin();\n this.hcs2Plugin = new HCS2Plugin();\n this.inscribePlugin = new InscribePlugin();\n this.hbarTransferPlugin = new HbarTransferPlugin();\n this.logger = new Logger({\n module: 'ConversationalAgent',\n silent: options.disableLogging || false,\n });\n }\n\n /**\n * Initialize the conversational agent with Hedera network connection and AI configuration\n * @throws {Error} If account ID or private key is missing\n * @throws {Error} If initialization fails\n */\n async initialize(): Promise<void> {\n const {\n accountId,\n privateKey,\n network = DEFAULT_NETWORK,\n openAIApiKey,\n openAIModelName = DEFAULT_MODEL_NAME,\n verbose = false,\n operationalMode = DEFAULT_OPERATIONAL_MODE,\n userAccountId,\n customSystemMessagePreamble,\n customSystemMessagePostamble,\n additionalPlugins = [],\n mirrorNodeConfig,\n disableLogging,\n scheduleUserTransactionsInBytesMode,\n } = this.options;\n\n if (!accountId || !privateKey) {\n throw new Error('Account ID and private key are required');\n }\n\n try {\n const privateKeyInstance = await this.detectPrivateKeyType(\n accountId,\n privateKey,\n network\n );\n\n const serverSigner = new ServerSigner(\n accountId,\n privateKeyInstance,\n network as 'testnet' | 'mainnet' | 'previewnet'\n );\n\n const standardPlugins = [\n this.hcs10Plugin,\n this.hcs2Plugin,\n this.inscribePlugin,\n this.hbarTransferPlugin,\n ];\n\n const corePlugins = getAllHederaCorePlugins();\n\n let allPlugins: BasePlugin[];\n\n if (this.options.enabledPlugins) {\n const enabledSet = new Set(this.options.enabledPlugins);\n const filteredPlugins = [...standardPlugins, ...corePlugins].filter(\n (plugin) => enabledSet.has(plugin.id)\n );\n allPlugins = [...filteredPlugins, ...additionalPlugins];\n } else {\n allPlugins = [...standardPlugins, ...corePlugins, ...additionalPlugins];\n }\n\n const llm = new ChatOpenAI({\n apiKey: openAIApiKey,\n modelName: openAIModelName,\n temperature: DEFAULT_TEMPERATURE,\n });\n\n this.agent = createAgent({\n framework: 'langchain',\n signer: serverSigner,\n execution: {\n mode: operationalMode === 'autonomous' ? 'direct' : 'bytes',\n operationalMode: operationalMode,\n ...(userAccountId && { userAccountId }),\n ...(scheduleUserTransactionsInBytesMode !== undefined && {\n scheduleUserTransactions: scheduleUserTransactionsInBytesMode,\n }),\n },\n ai: {\n provider: new LangChainProvider(llm),\n temperature: DEFAULT_TEMPERATURE,\n },\n filtering: {\n toolPredicate: (tool) => {\n if (tool.name === 'hedera-account-transfer-hbar') return false;\n if (this.options.toolFilter && !this.options.toolFilter(tool)) {\n return false;\n }\n return true;\n },\n },\n messaging: {\n systemPreamble:\n customSystemMessagePreamble || getSystemMessage(accountId),\n ...(customSystemMessagePostamble && { systemPostamble: customSystemMessagePostamble }),\n conciseMode: true,\n },\n extensions: {\n plugins: allPlugins,\n ...(mirrorNodeConfig && {\n mirrorConfig: mirrorNodeConfig as Record<string, unknown>,\n }),\n },\n ...(this.options.mcpServers && {\n mcp: {\n servers: this.options.mcpServers,\n autoConnect: true,\n },\n }),\n debug: {\n verbose,\n silent: disableLogging ?? false,\n },\n });\n\n const hcs10 = allPlugins.find((p) => p.id === 'hcs-10');\n if (hcs10) {\n (hcs10 as { appConfig?: Record<string, unknown> }).appConfig = {\n stateManager: this.stateManager,\n };\n }\n\n await this.agent.boot();\n } catch (error) {\n this.logger.error('Failed to initialize ConversationalAgent:', error);\n throw error;\n }\n }\n\n /**\n * Get the HCS-10 plugin instance\n * @returns {HCS10Plugin} The HCS-10 plugin instance\n */\n getPlugin(): HCS10Plugin {\n return this.hcs10Plugin;\n }\n\n /**\n * Get the state manager instance\n * @returns {IStateManager} The state manager instance\n */\n getStateManager(): IStateManager {\n return this.stateManager;\n }\n\n /**\n * Get the underlying agent instance\n * @returns {ReturnType<typeof createAgent>} The agent instance\n * @throws {Error} If agent is not initialized\n */\n getAgent(): ReturnType<typeof createAgent> {\n if (!this.agent) {\n throw new Error('Agent not initialized. Call initialize() first.');\n }\n return this.agent;\n }\n\n /**\n * Get the conversational agent instance (alias for getAgent)\n * @returns {ReturnType<typeof createAgent>} The agent instance\n * @throws {Error} If agent is not initialized\n */\n getConversationalAgent(): ReturnType<typeof createAgent> {\n return this.getAgent();\n }\n\n /**\n * Process a message through the conversational agent\n * @param {string} message - The message to process\n * @param {Array<{type: 'human' | 'ai'; content: string}>} chatHistory - Previous chat history\n * @returns {Promise<ChatResponse>} The agent's response\n * @throws {Error} If agent is not initialized\n */\n async processMessage(\n message: string,\n chatHistory: {\n type: 'human' | 'ai';\n content: string;\n }[] = []\n ): Promise<ChatResponse> {\n if (!this.agent) {\n throw new Error('Agent not initialized. Call initialize() first.');\n }\n\n const messages = chatHistory.map((msg) =>\n msg.type === 'human'\n ? new HumanMessage(msg.content)\n : new AIMessage(msg.content)\n );\n\n const context: ConversationContext = {\n messages,\n };\n\n return this.agent.chat(message, context);\n }\n\n /**\n * Create a ConversationalAgent with specific plugins enabled\n */\n private static withPlugins(\n options: ConversationalAgentOptions,\n plugins: string[]\n ): ConversationalAgent {\n return new ConversationalAgent({\n ...options,\n enabledPlugins: plugins,\n });\n }\n\n /**\n * Create a ConversationalAgent with only HTS (Hedera Token Service) tools enabled\n */\n static withHTS(options: ConversationalAgentOptions): ConversationalAgent {\n return this.withPlugins(options, ['hts-token']);\n }\n\n /**\n * Create a ConversationalAgent with only HCS-2 tools enabled\n */\n static withHCS2(options: ConversationalAgentOptions): ConversationalAgent {\n return this.withPlugins(options, ['hcs-2']);\n }\n\n /**\n * Create a ConversationalAgent with only HCS-10 tools enabled\n */\n static withHCS10(options: ConversationalAgentOptions): ConversationalAgent {\n return this.withPlugins(options, ['hcs-10']);\n }\n\n /**\n * Create a ConversationalAgent with only inscription tools enabled\n */\n static withInscribe(\n options: ConversationalAgentOptions\n ): ConversationalAgent {\n return this.withPlugins(options, ['inscribe']);\n }\n\n /**\n * Create a ConversationalAgent with only account management tools enabled\n */\n static withAccount(options: ConversationalAgentOptions): ConversationalAgent {\n return this.withPlugins(options, ['account']);\n }\n\n /**\n * Create a ConversationalAgent with only file service tools enabled\n */\n static withFileService(\n options: ConversationalAgentOptions\n ): ConversationalAgent {\n return this.withPlugins(options, ['file-service']);\n }\n\n /**\n * Create a ConversationalAgent with only consensus service tools enabled\n */\n static withConsensusService(\n options: ConversationalAgentOptions\n ): ConversationalAgent {\n return this.withPlugins(options, ['consensus-service']);\n }\n\n /**\n * Create a ConversationalAgent with only smart contract tools enabled\n */\n static withSmartContract(\n options: ConversationalAgentOptions\n ): ConversationalAgent {\n return this.withPlugins(options, ['smart-contract']);\n }\n\n /**\n * Create a ConversationalAgent with all HCS standards plugins\n */\n static withAllStandards(\n options: ConversationalAgentOptions\n ): ConversationalAgent {\n return this.withPlugins(options, ['hcs-10', 'hcs-2', 'inscribe']);\n }\n\n /**\n * Create a ConversationalAgent with minimal Hedera tools (no HCS standards)\n */\n static minimal(options: ConversationalAgentOptions): ConversationalAgent {\n return this.withPlugins(options, []);\n }\n\n /**\n * Create a ConversationalAgent with MCP servers configured\n */\n static withMCP(\n options: ConversationalAgentOptions,\n mcpServers: MCPServerConfig[]\n ): ConversationalAgent {\n return new ConversationalAgent({\n ...options,\n mcpServers,\n });\n }\n\n /**\n * Detect the private key type by querying the account info from mirror node\n * @param {string} accountId - The Hedera account ID\n * @param {string} privateKey - The private key string\n * @param {NetworkType} network - The Hedera network\n * @returns {Promise<PrivateKey>} The appropriate PrivateKey instance\n */\n private async detectPrivateKeyType(\n accountId: string,\n privateKey: string,\n network: NetworkType\n ): Promise<PrivateKey> {\n const mirrorNode = new HederaMirrorNode(network as 'testnet' | 'mainnet');\n const accountInfo = await mirrorNode.requestAccount(accountId);\n\n const keyType = accountInfo?.key?._type || '';\n\n if (keyType?.toLowerCase()?.includes('ecdsa')) {\n return PrivateKey.fromStringECDSA(privateKey);\n } else {\n return PrivateKey.fromStringED25519(privateKey);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Logger } from "@hashgraphonline/standards-sdk";
|
|
2
|
+
class BaseAgent {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.config = config;
|
|
5
|
+
this.tools = [];
|
|
6
|
+
this.initialized = false;
|
|
7
|
+
this.logger = new Logger({
|
|
8
|
+
module: "BaseAgent",
|
|
9
|
+
silent: config.debug?.silent || false
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
getCore() {
|
|
13
|
+
return this.agentKit;
|
|
14
|
+
}
|
|
15
|
+
filterTools(tools) {
|
|
16
|
+
let filtered = [...tools];
|
|
17
|
+
const filter = this.config.filtering;
|
|
18
|
+
if (!filter) return filtered;
|
|
19
|
+
if (filter.namespaceWhitelist?.length) {
|
|
20
|
+
filtered = filtered.filter((tool) => {
|
|
21
|
+
const namespace = tool.namespace;
|
|
22
|
+
return !namespace || filter.namespaceWhitelist.includes(namespace);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (filter.toolBlacklist?.length) {
|
|
26
|
+
filtered = filtered.filter(
|
|
27
|
+
(tool) => !filter.toolBlacklist.includes(tool.name)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (filter.toolPredicate) {
|
|
31
|
+
filtered = filtered.filter(filter.toolPredicate);
|
|
32
|
+
}
|
|
33
|
+
this.logger.debug(`Filtered tools: ${tools.length} → ${filtered.length}`);
|
|
34
|
+
return filtered;
|
|
35
|
+
}
|
|
36
|
+
buildSystemPrompt() {
|
|
37
|
+
const parts = [];
|
|
38
|
+
const operatorId = this.config.signer.getAccountId().toString();
|
|
39
|
+
const userAccId = this.config.execution?.userAccountId;
|
|
40
|
+
if (this.config.messaging?.systemPreamble) {
|
|
41
|
+
parts.push(this.config.messaging.systemPreamble);
|
|
42
|
+
}
|
|
43
|
+
parts.push(
|
|
44
|
+
`You are a helpful Hedera assistant. Your primary operator account is ${operatorId}. You have tools to interact with the Hedera network. When using any tool, provide all necessary parameters as defined by that tool's schema and description.`
|
|
45
|
+
);
|
|
46
|
+
if (userAccId) {
|
|
47
|
+
parts.push(
|
|
48
|
+
`The user you are assisting has a personal Hedera account ID: ${userAccId}. IMPORTANT: When the user says things like "I want to send HBAR" or "transfer my tokens", you MUST use ${userAccId} as the sender/from account. For example, if user says "I want to send 2 HBAR to 0.0.800", you must set up a transfer where ${userAccId} sends the HBAR, not your operator account.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const operationalMode = this.config.execution?.operationalMode || "returnBytes";
|
|
52
|
+
if (operationalMode === "autonomous") {
|
|
53
|
+
parts.push(
|
|
54
|
+
`
|
|
55
|
+
OPERATIONAL MODE: 'autonomous'. Your goal is to execute transactions directly using your tools. Your account ${operatorId} will be the payer for these transactions. Even if the user's account (${userAccId || "a specified account"}) is the actor in the transaction body (e.g., sender of HBAR), you (the agent with operator ${operatorId}) are still executing and paying. For HBAR transfers, ensure the amounts in the 'transfers' array sum to zero (as per tool schema), balancing with your operator account if necessary.`
|
|
56
|
+
);
|
|
57
|
+
} else {
|
|
58
|
+
if (this.config.execution?.scheduleUserTransactionsInBytesMode && userAccId) {
|
|
59
|
+
parts.push(
|
|
60
|
+
`
|
|
61
|
+
OPERATIONAL MODE: 'returnBytes' with scheduled transactions for user actions. When a user asks for a transaction to be prepared (e.g., creating a token, topic, transferring assets for them to sign, etc), you MUST default to creating a Scheduled Transaction using the appropriate tool with the metaOption 'schedule: true'. The user (with account ID ${userAccId}) will be the one to ultimately pay for and (if needed) sign the inner transaction. Your operator account (${operatorId}) will pay for creating the schedule entity itself. You MUST return the ScheduleId and details of the scheduled operation in a structured JSON format with these fields: success, op, schedule_id, description, payer_account_id_scheduled_tx, and scheduled_transaction_details.`
|
|
62
|
+
);
|
|
63
|
+
} else {
|
|
64
|
+
parts.push(
|
|
65
|
+
`
|
|
66
|
+
OPERATIONAL MODE: 'returnBytes'. Your goal is to provide transaction bytes directly. When a user asks for a transaction to be prepared (e.g., for them to sign, or for scheduling without the default scheduling flow), you MUST call the appropriate tool. If you want raw bytes for the user to sign for their own account ${userAccId || "if specified"}, ensure the tool constructs the transaction body accordingly and use metaOption 'returnBytes: true' if available, or ensure the builder is configured for the user.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (this.config.messaging?.conciseMode !== false) {
|
|
71
|
+
parts.push(
|
|
72
|
+
"\nAlways be concise. If the tool provides a JSON string as its primary output (especially in returnBytes mode), make your accompanying text brief. If the tool does not provide JSON output or an error occurs, your narrative becomes primary; if notes were generated by the tool in such cases, append them to your textual response."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (this.config.messaging?.systemPostamble) {
|
|
76
|
+
parts.push(this.config.messaging.systemPostamble);
|
|
77
|
+
}
|
|
78
|
+
return parts.join("\n");
|
|
79
|
+
}
|
|
80
|
+
isReady() {
|
|
81
|
+
return this.initialized;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
BaseAgent
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=index7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index7.js","sources":["../../src/base-agent.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport type { StructuredTool } from '@langchain/core/tools';\nimport type { TransactionReceipt } from '@hashgraph/sdk';\nimport {\n HederaAgentKit,\n ServerSigner,\n TokenUsageCallbackHandler,\n TokenUsage,\n BasePlugin,\n} from 'hedera-agent-kit';\nimport type { CostCalculation } from 'hedera-agent-kit';\nimport type { AIProvider, VercelAIProvider, BAMLProvider } from './providers';\nimport { Logger } from '@hashgraphonline/standards-sdk';\nimport type { MCPServerConfig } from './mcp/types';\n\nexport interface ToolFilterConfig {\n namespaceWhitelist?: string[];\n toolBlacklist?: string[];\n toolPredicate?: (tool: StructuredTool) => boolean;\n}\n\nexport type ExecutionMode = 'direct' | 'bytes';\nexport type OperationalMode = 'autonomous' | 'returnBytes';\n\nexport interface HederaAgentConfiguration {\n signer: ServerSigner;\n execution?: {\n mode?: ExecutionMode;\n operationalMode?: OperationalMode;\n userAccountId?: string;\n scheduleUserTransactions?: boolean;\n scheduleUserTransactionsInBytesMode?: boolean;\n };\n ai?: {\n provider?: AIProvider;\n llm?: unknown;\n apiKey?: string;\n modelName?: string;\n temperature?: number;\n };\n filtering?: ToolFilterConfig;\n messaging?: {\n systemPreamble?: string;\n systemPostamble?: string;\n conciseMode?: boolean;\n };\n extensions?: {\n plugins?: BasePlugin[];\n mirrorConfig?: Record<string, unknown>;\n modelCapability?: string;\n };\n mcp?: {\n servers?: MCPServerConfig[];\n autoConnect?: boolean;\n };\n debug?: {\n verbose?: boolean;\n silent?: boolean;\n };\n}\n\nexport interface ConversationContext {\n messages: BaseMessage[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface ChatResponse {\n output: string;\n message?: string;\n transactionBytes?: string;\n receipt?: TransactionReceipt | object;\n scheduleId?: string;\n transactionId?: string;\n notes?: string[];\n error?: string;\n intermediateSteps?: unknown;\n rawToolOutput?: unknown;\n tokenUsage?: TokenUsage;\n cost?: CostCalculation;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface UsageStats extends TokenUsage {\n cost: CostCalculation;\n}\n\nexport abstract class BaseAgent {\n protected logger: Logger;\n protected agentKit: HederaAgentKit | undefined;\n protected tools: StructuredTool[] = [];\n protected initialized = false;\n protected tokenTracker: TokenUsageCallbackHandler | undefined;\n\n constructor(protected config: HederaAgentConfiguration) {\n this.logger = new Logger({\n module: 'BaseAgent',\n silent: config.debug?.silent || false,\n });\n }\n\n abstract boot(): Promise<void>;\n abstract chat(\n message: string,\n context?: ConversationContext\n ): Promise<ChatResponse>;\n abstract shutdown(): Promise<void>;\n abstract switchMode(mode: OperationalMode): void;\n abstract getUsageStats(): UsageStats;\n abstract getUsageLog(): UsageStats[];\n abstract clearUsageStats(): void;\n\n getCore(): HederaAgentKit | undefined {\n return this.agentKit;\n }\n\n protected filterTools(\n tools: StructuredTool[]\n ): StructuredTool[] {\n let filtered = [...tools];\n const filter = this.config.filtering;\n if (!filter) return filtered;\n\n if (filter.namespaceWhitelist?.length) {\n filtered = filtered.filter((tool) => {\n const namespace = (tool as StructuredTool & { namespace?: string })\n .namespace;\n return !namespace || filter.namespaceWhitelist!.includes(namespace);\n });\n }\n\n if (filter.toolBlacklist?.length) {\n filtered = filtered.filter(\n (tool) => !filter.toolBlacklist!.includes(tool.name)\n );\n }\n\n if (filter.toolPredicate) {\n filtered = filtered.filter(filter.toolPredicate);\n }\n\n this.logger.debug(`Filtered tools: ${tools.length} → ${filtered.length}`);\n return filtered;\n }\n\n protected buildSystemPrompt(): string {\n const parts: string[] = [];\n const operatorId = this.config.signer.getAccountId().toString();\n const userAccId = this.config.execution?.userAccountId;\n\n if (this.config.messaging?.systemPreamble) {\n parts.push(this.config.messaging.systemPreamble);\n }\n\n parts.push(\n `You are a helpful Hedera assistant. Your primary operator account is ${operatorId}. ` +\n `You have tools to interact with the Hedera network. ` +\n `When using any tool, provide all necessary parameters as defined by that tool's schema and description.`\n );\n\n if (userAccId) {\n parts.push(\n `The user you are assisting has a personal Hedera account ID: ${userAccId}. ` +\n `IMPORTANT: When the user says things like \"I want to send HBAR\" or \"transfer my tokens\", you MUST use ${userAccId} as the sender/from account. ` +\n `For example, if user says \"I want to send 2 HBAR to 0.0.800\", you must set up a transfer where ${userAccId} sends the HBAR, not your operator account.`\n );\n }\n\n const operationalMode =\n this.config.execution?.operationalMode || 'returnBytes';\n if (operationalMode === 'autonomous') {\n parts.push(\n `\\nOPERATIONAL MODE: 'autonomous'. Your goal is to execute transactions directly using your tools. ` +\n `Your account ${operatorId} will be the payer for these transactions. ` +\n `Even if the user's account (${\n userAccId || 'a specified account'\n }) is the actor in the transaction body (e.g., sender of HBAR), ` +\n `you (the agent with operator ${operatorId}) are still executing and paying. For HBAR transfers, ensure the amounts in the 'transfers' array sum to zero (as per tool schema), balancing with your operator account if necessary.`\n );\n } else {\n if (\n this.config.execution?.scheduleUserTransactionsInBytesMode &&\n userAccId\n ) {\n parts.push(\n `\\nOPERATIONAL MODE: 'returnBytes' with scheduled transactions for user actions. ` +\n `When a user asks for a transaction to be prepared (e.g., creating a token, topic, transferring assets for them to sign, etc), ` +\n `you MUST default to creating a Scheduled Transaction using the appropriate tool with the metaOption 'schedule: true'. ` +\n `The user (with account ID ${userAccId}) will be the one to ultimately pay for and (if needed) sign the inner transaction. ` +\n `Your operator account (${operatorId}) will pay for creating the schedule entity itself. ` +\n `You MUST return the ScheduleId and details of the scheduled operation in a structured JSON format with these fields: success, op, schedule_id, description, payer_account_id_scheduled_tx, and scheduled_transaction_details.`\n );\n } else {\n parts.push(\n `\\nOPERATIONAL MODE: 'returnBytes'. Your goal is to provide transaction bytes directly. ` +\n `When a user asks for a transaction to be prepared (e.g., for them to sign, or for scheduling without the default scheduling flow), ` +\n `you MUST call the appropriate tool. If you want raw bytes for the user to sign for their own account ${\n userAccId || 'if specified'\n }, ensure the tool constructs the transaction body accordingly and use metaOption 'returnBytes: true' if available, or ensure the builder is configured for the user.`\n );\n }\n }\n\n if (this.config.messaging?.conciseMode !== false) {\n parts.push(\n '\\nAlways be concise. If the tool provides a JSON string as its primary output (especially in returnBytes mode), make your accompanying text brief. If the tool does not provide JSON output or an error occurs, your narrative becomes primary; if notes were generated by the tool in such cases, append them to your textual response.'\n );\n }\n\n if (this.config.messaging?.systemPostamble) {\n parts.push(this.config.messaging.systemPostamble);\n }\n\n return parts.join('\\n');\n }\n\n isReady(): boolean {\n return this.initialized;\n }\n}\n\nexport type { AIProvider, VercelAIProvider, BAMLProvider };\n"],"names":[],"mappings":";AAuFO,MAAe,UAAU;AAAA,EAO9B,YAAsB,QAAkC;AAAlC,SAAA,SAAA;AAJtB,SAAU,QAA0B,CAAA;AACpC,SAAU,cAAc;AAItB,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,QAAQ;AAAA,MACR,QAAQ,OAAO,OAAO,UAAU;AAAA,IAAA,CACjC;AAAA,EACH;AAAA,EAaA,UAAsC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEU,YACR,OACkB;AAClB,QAAI,WAAW,CAAC,GAAG,KAAK;AACxB,UAAM,SAAS,KAAK,OAAO;AAC3B,QAAI,CAAC,OAAQ,QAAO;AAEpB,QAAI,OAAO,oBAAoB,QAAQ;AACrC,iBAAW,SAAS,OAAO,CAAC,SAAS;AACnC,cAAM,YAAa,KAChB;AACH,eAAO,CAAC,aAAa,OAAO,mBAAoB,SAAS,SAAS;AAAA,MACpE,CAAC;AAAA,IACH;AAEA,QAAI,OAAO,eAAe,QAAQ;AAChC,iBAAW,SAAS;AAAA,QAClB,CAAC,SAAS,CAAC,OAAO,cAAe,SAAS,KAAK,IAAI;AAAA,MAAA;AAAA,IAEvD;AAEA,QAAI,OAAO,eAAe;AACxB,iBAAW,SAAS,OAAO,OAAO,aAAa;AAAA,IACjD;AAEA,SAAK,OAAO,MAAM,mBAAmB,MAAM,MAAM,MAAM,SAAS,MAAM,EAAE;AACxE,WAAO;AAAA,EACT;AAAA,EAEU,oBAA4B;AACpC,UAAM,QAAkB,CAAA;AACxB,UAAM,aAAa,KAAK,OAAO,OAAO,aAAA,EAAe,SAAA;AACrD,UAAM,YAAY,KAAK,OAAO,WAAW;AAEzC,QAAI,KAAK,OAAO,WAAW,gBAAgB;AACzC,YAAM,KAAK,KAAK,OAAO,UAAU,cAAc;AAAA,IACjD;AAEA,UAAM;AAAA,MACJ,wEAAwE,UAAU;AAAA,IAAA;AAKpF,QAAI,WAAW;AACb,YAAM;AAAA,QACJ,gEAAgE,SAAS,2GACkC,SAAS,+HAChB,SAAS;AAAA,MAAA;AAAA,IAEjH;AAEA,UAAM,kBACJ,KAAK,OAAO,WAAW,mBAAmB;AAC5C,QAAI,oBAAoB,cAAc;AACpC,YAAM;AAAA,QACJ;AAAA,+GACkB,UAAU,0EAExB,aAAa,qBACf,+FACgC,UAAU;AAAA,MAAA;AAAA,IAEhD,OAAO;AACL,UACE,KAAK,OAAO,WAAW,uCACvB,WACA;AACA,cAAM;AAAA,UACJ;AAAA,8VAG+B,SAAS,8GACZ,UAAU;AAAA,QAAA;AAAA,MAG1C,OAAO;AACL,cAAM;AAAA,UACJ;AAAA,+TAGI,aAAa,cACf;AAAA,QAAA;AAAA,MAEN;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,WAAW,gBAAgB,OAAO;AAChD,YAAM;AAAA,QACJ;AAAA,MAAA;AAAA,IAEJ;AAEA,QAAI,KAAK,OAAO,WAAW,iBAAiB;AAC1C,YAAM,KAAK,KAAK,OAAO,UAAU,eAAe;AAAA,IAClD;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AACF;"}
|