@moly-mcp/lido 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +21 -6
- package/dist/chunk-RE3UIDLV.js +545 -0
- package/dist/server/index.js +18 -526
- package/dist/session-55BKKXQV.js +494 -0
- package/package.json +1 -1
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
castVote,
|
|
4
|
+
claimWithdrawals,
|
|
5
|
+
getBalance,
|
|
6
|
+
getConversionRate,
|
|
7
|
+
getProposal,
|
|
8
|
+
getProposals,
|
|
9
|
+
getRewards,
|
|
10
|
+
getSettings,
|
|
11
|
+
getWithdrawalRequests,
|
|
12
|
+
getWithdrawalStatus,
|
|
13
|
+
requestWithdrawal,
|
|
14
|
+
stakeEth,
|
|
15
|
+
unwrapWsteth,
|
|
16
|
+
updateSettings,
|
|
17
|
+
wrapSteth
|
|
18
|
+
} from "./chunk-RE3UIDLV.js";
|
|
19
|
+
import "./chunk-PIFEXJ56.js";
|
|
20
|
+
|
|
21
|
+
// src/chat/session.ts
|
|
22
|
+
import * as readline from "readline";
|
|
23
|
+
|
|
24
|
+
// src/chat/providers.ts
|
|
25
|
+
async function callAnthropic(apiKey, model, messages, tools) {
|
|
26
|
+
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
"x-api-key": apiKey,
|
|
30
|
+
"anthropic-version": "2023-06-01",
|
|
31
|
+
"content-type": "application/json"
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
model,
|
|
35
|
+
max_tokens: 4096,
|
|
36
|
+
messages,
|
|
37
|
+
tools: tools.map((t) => ({
|
|
38
|
+
name: t.name,
|
|
39
|
+
description: t.description,
|
|
40
|
+
input_schema: t.parameters
|
|
41
|
+
}))
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const err = await res.text();
|
|
46
|
+
throw new Error(`Anthropic API error ${res.status}: ${err}`);
|
|
47
|
+
}
|
|
48
|
+
const data = await res.json();
|
|
49
|
+
const content = data.content;
|
|
50
|
+
const textBlock = content.find((b) => b.type === "text");
|
|
51
|
+
const toolUseBlocks = content.filter((b) => b.type === "tool_use");
|
|
52
|
+
return {
|
|
53
|
+
text: textBlock?.text ?? null,
|
|
54
|
+
toolCalls: toolUseBlocks.map((b) => ({
|
|
55
|
+
id: b.id,
|
|
56
|
+
name: b.name,
|
|
57
|
+
args: b.input
|
|
58
|
+
})),
|
|
59
|
+
rawAssistantMessage: { role: "assistant", content }
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function anthropicToolResult(toolCallId, result) {
|
|
63
|
+
return {
|
|
64
|
+
role: "user",
|
|
65
|
+
content: [{ type: "tool_result", tool_use_id: toolCallId, content: result }]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function callOpenRouter(apiKey, model, messages, tools) {
|
|
69
|
+
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: {
|
|
72
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
"HTTP-Referer": "https://github.com/daiwikmh/moly",
|
|
75
|
+
"X-Title": "Moly \u2014 Lido MCP"
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
model,
|
|
79
|
+
messages,
|
|
80
|
+
tools: tools.map((t) => ({
|
|
81
|
+
type: "function",
|
|
82
|
+
function: { name: t.name, description: t.description, parameters: t.parameters }
|
|
83
|
+
}))
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
const err = await res.text();
|
|
88
|
+
throw new Error(`OpenRouter API error ${res.status}: ${err}`);
|
|
89
|
+
}
|
|
90
|
+
const data = await res.json();
|
|
91
|
+
const msg = data.choices[0].message;
|
|
92
|
+
return {
|
|
93
|
+
text: msg.content ?? null,
|
|
94
|
+
toolCalls: (msg.tool_calls ?? []).map((tc) => ({
|
|
95
|
+
id: tc.id,
|
|
96
|
+
name: tc.function.name,
|
|
97
|
+
args: JSON.parse(tc.function.arguments ?? "{}")
|
|
98
|
+
})),
|
|
99
|
+
rawAssistantMessage: { role: "assistant", content: msg.content, tool_calls: msg.tool_calls }
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function callGemini(apiKey, model, messages, tools) {
|
|
103
|
+
const contents = messages.map((m) => ({
|
|
104
|
+
role: m.role === "assistant" ? "model" : "user",
|
|
105
|
+
parts: Array.isArray(m.content) ? m.content : [{ text: m.content }]
|
|
106
|
+
}));
|
|
107
|
+
const res = await fetch(
|
|
108
|
+
`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`,
|
|
109
|
+
{
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "content-type": "application/json" },
|
|
112
|
+
body: JSON.stringify({
|
|
113
|
+
contents,
|
|
114
|
+
tools: [{
|
|
115
|
+
functionDeclarations: tools.map((t) => ({
|
|
116
|
+
name: t.name,
|
|
117
|
+
description: t.description,
|
|
118
|
+
parameters: t.parameters
|
|
119
|
+
}))
|
|
120
|
+
}]
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
if (!res.ok) {
|
|
125
|
+
const err = await res.text();
|
|
126
|
+
throw new Error(`Gemini API error ${res.status}: ${err}`);
|
|
127
|
+
}
|
|
128
|
+
const data = await res.json();
|
|
129
|
+
const parts = data.candidates?.[0]?.content?.parts ?? [];
|
|
130
|
+
const textPart = parts.find((p) => p.text);
|
|
131
|
+
const fnCalls = parts.filter((p) => p.functionCall);
|
|
132
|
+
return {
|
|
133
|
+
text: textPart?.text ?? null,
|
|
134
|
+
toolCalls: fnCalls.map((p, i) => ({
|
|
135
|
+
id: `gemini-${i}`,
|
|
136
|
+
name: p.functionCall.name,
|
|
137
|
+
args: p.functionCall.args ?? {}
|
|
138
|
+
})),
|
|
139
|
+
rawAssistantMessage: {
|
|
140
|
+
role: "model",
|
|
141
|
+
parts
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function geminiToolResult(toolCallId, name, result) {
|
|
146
|
+
return {
|
|
147
|
+
role: "user",
|
|
148
|
+
content: [{ functionResponse: { name, response: { output: result } } }]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function callAi(provider, apiKey, model, messages, tools) {
|
|
152
|
+
switch (provider) {
|
|
153
|
+
case "anthropic":
|
|
154
|
+
return callAnthropic(apiKey, model, messages, tools);
|
|
155
|
+
case "openrouter":
|
|
156
|
+
return callOpenRouter(apiKey, model, messages, tools);
|
|
157
|
+
case "google":
|
|
158
|
+
return callGemini(apiKey, model, messages, tools);
|
|
159
|
+
default:
|
|
160
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function makeToolResultMessage(provider, toolCallId, toolName, result) {
|
|
164
|
+
switch (provider) {
|
|
165
|
+
case "anthropic":
|
|
166
|
+
return anthropicToolResult(toolCallId, result);
|
|
167
|
+
case "openrouter":
|
|
168
|
+
return { role: "tool", content: result, ...{ tool_call_id: toolCallId } };
|
|
169
|
+
case "google":
|
|
170
|
+
return geminiToolResult(toolCallId, toolName, result);
|
|
171
|
+
default:
|
|
172
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/chat/tools.ts
|
|
177
|
+
var TOOL_DEFS = [
|
|
178
|
+
{
|
|
179
|
+
name: "get_balance",
|
|
180
|
+
description: "Get ETH, stETH, and wstETH balances for an address.",
|
|
181
|
+
parameters: {
|
|
182
|
+
type: "object",
|
|
183
|
+
properties: {
|
|
184
|
+
address: { type: "string", description: "Ethereum address (optional, defaults to configured wallet)" }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "get_rewards",
|
|
190
|
+
description: "Get staking reward history for an address over N days.",
|
|
191
|
+
parameters: {
|
|
192
|
+
type: "object",
|
|
193
|
+
properties: {
|
|
194
|
+
address: { type: "string", description: "Ethereum address (optional)" },
|
|
195
|
+
days: { type: "number", description: "Days to look back (1-365), default 7" }
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "get_conversion_rate",
|
|
201
|
+
description: "Get current stETH \u2194 wstETH conversion rates.",
|
|
202
|
+
parameters: { type: "object", properties: {} }
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "stake_eth",
|
|
206
|
+
description: "Stake ETH to receive stETH (liquid staking).",
|
|
207
|
+
parameters: {
|
|
208
|
+
type: "object",
|
|
209
|
+
required: ["amount_eth"],
|
|
210
|
+
properties: {
|
|
211
|
+
amount_eth: { type: "string", description: 'Amount of ETH to stake (e.g. "0.1")' },
|
|
212
|
+
dry_run: { type: "boolean", description: "Simulate without broadcasting" }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: "request_withdrawal",
|
|
218
|
+
description: "Request withdrawal of stETH back to ETH. Min 0.1, max 1000 stETH.",
|
|
219
|
+
parameters: {
|
|
220
|
+
type: "object",
|
|
221
|
+
required: ["amount_steth"],
|
|
222
|
+
properties: {
|
|
223
|
+
amount_steth: { type: "string", description: "Amount of stETH to withdraw" },
|
|
224
|
+
dry_run: { type: "boolean" }
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "claim_withdrawals",
|
|
230
|
+
description: "Claim finalized withdrawal requests and receive ETH.",
|
|
231
|
+
parameters: {
|
|
232
|
+
type: "object",
|
|
233
|
+
required: ["request_ids"],
|
|
234
|
+
properties: {
|
|
235
|
+
request_ids: { type: "array", items: { type: "string" }, description: "Withdrawal request NFT IDs" },
|
|
236
|
+
dry_run: { type: "boolean" }
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "get_withdrawal_requests",
|
|
242
|
+
description: "Get all pending withdrawal request IDs for an address.",
|
|
243
|
+
parameters: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
address: { type: "string", description: "Ethereum address (optional)" }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: "get_withdrawal_status",
|
|
252
|
+
description: "Check finalization status of withdrawal request IDs.",
|
|
253
|
+
parameters: {
|
|
254
|
+
type: "object",
|
|
255
|
+
required: ["request_ids"],
|
|
256
|
+
properties: {
|
|
257
|
+
request_ids: { type: "array", items: { type: "string" } }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "wrap_steth",
|
|
263
|
+
description: "Wrap stETH into wstETH.",
|
|
264
|
+
parameters: {
|
|
265
|
+
type: "object",
|
|
266
|
+
required: ["amount_steth"],
|
|
267
|
+
properties: {
|
|
268
|
+
amount_steth: { type: "string" },
|
|
269
|
+
dry_run: { type: "boolean" }
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: "unwrap_wsteth",
|
|
275
|
+
description: "Unwrap wstETH back to stETH.",
|
|
276
|
+
parameters: {
|
|
277
|
+
type: "object",
|
|
278
|
+
required: ["amount_wsteth"],
|
|
279
|
+
properties: {
|
|
280
|
+
amount_wsteth: { type: "string" },
|
|
281
|
+
dry_run: { type: "boolean" }
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "get_proposals",
|
|
287
|
+
description: "List recent Lido DAO governance proposals.",
|
|
288
|
+
parameters: {
|
|
289
|
+
type: "object",
|
|
290
|
+
properties: {
|
|
291
|
+
count: { type: "number", description: "Number of proposals (1-20, default 5)" }
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: "get_proposal",
|
|
297
|
+
description: "Get detailed info on a specific Lido DAO governance proposal.",
|
|
298
|
+
parameters: {
|
|
299
|
+
type: "object",
|
|
300
|
+
required: ["proposal_id"],
|
|
301
|
+
properties: {
|
|
302
|
+
proposal_id: { type: "number" }
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: "cast_vote",
|
|
308
|
+
description: "Vote YEA or NAY on a Lido DAO governance proposal.",
|
|
309
|
+
parameters: {
|
|
310
|
+
type: "object",
|
|
311
|
+
required: ["proposal_id", "support"],
|
|
312
|
+
properties: {
|
|
313
|
+
proposal_id: { type: "number" },
|
|
314
|
+
support: { type: "boolean", description: "true = YEA, false = NAY" },
|
|
315
|
+
dry_run: { type: "boolean" }
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "get_settings",
|
|
321
|
+
description: "Get current Moly configuration.",
|
|
322
|
+
parameters: { type: "object", properties: {} }
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "update_settings",
|
|
326
|
+
description: "Change mode, network, or RPC.",
|
|
327
|
+
parameters: {
|
|
328
|
+
type: "object",
|
|
329
|
+
properties: {
|
|
330
|
+
network: { type: "string", enum: ["hoodi", "mainnet"] },
|
|
331
|
+
mode: { type: "string", enum: ["simulation", "live"] },
|
|
332
|
+
rpc: { type: "string", nullable: true },
|
|
333
|
+
model: { type: "string" }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
async function executeTool(name, args) {
|
|
339
|
+
try {
|
|
340
|
+
let result;
|
|
341
|
+
switch (name) {
|
|
342
|
+
case "get_balance":
|
|
343
|
+
result = await getBalance(args.address);
|
|
344
|
+
break;
|
|
345
|
+
case "get_rewards":
|
|
346
|
+
result = await getRewards(args.address, args.days);
|
|
347
|
+
break;
|
|
348
|
+
case "get_conversion_rate":
|
|
349
|
+
result = await getConversionRate();
|
|
350
|
+
break;
|
|
351
|
+
case "stake_eth":
|
|
352
|
+
result = await stakeEth(args.amount_eth, args.dry_run);
|
|
353
|
+
break;
|
|
354
|
+
case "request_withdrawal":
|
|
355
|
+
result = await requestWithdrawal(args.amount_steth, args.dry_run);
|
|
356
|
+
break;
|
|
357
|
+
case "claim_withdrawals":
|
|
358
|
+
result = await claimWithdrawals(args.request_ids, args.dry_run);
|
|
359
|
+
break;
|
|
360
|
+
case "get_withdrawal_requests":
|
|
361
|
+
result = await getWithdrawalRequests(args.address);
|
|
362
|
+
break;
|
|
363
|
+
case "get_withdrawal_status":
|
|
364
|
+
result = await getWithdrawalStatus(args.request_ids);
|
|
365
|
+
break;
|
|
366
|
+
case "wrap_steth":
|
|
367
|
+
result = await wrapSteth(args.amount_steth, args.dry_run);
|
|
368
|
+
break;
|
|
369
|
+
case "unwrap_wsteth":
|
|
370
|
+
result = await unwrapWsteth(args.amount_wsteth, args.dry_run);
|
|
371
|
+
break;
|
|
372
|
+
case "get_proposals":
|
|
373
|
+
result = await getProposals(args.count);
|
|
374
|
+
break;
|
|
375
|
+
case "get_proposal":
|
|
376
|
+
result = await getProposal(args.proposal_id);
|
|
377
|
+
break;
|
|
378
|
+
case "cast_vote":
|
|
379
|
+
result = await castVote(args.proposal_id, args.support, args.dry_run);
|
|
380
|
+
break;
|
|
381
|
+
case "get_settings":
|
|
382
|
+
result = getSettings();
|
|
383
|
+
break;
|
|
384
|
+
case "update_settings":
|
|
385
|
+
result = updateSettings(args);
|
|
386
|
+
break;
|
|
387
|
+
default:
|
|
388
|
+
return `Unknown tool: ${name}`;
|
|
389
|
+
}
|
|
390
|
+
return JSON.stringify(result, null, 2);
|
|
391
|
+
} catch (err) {
|
|
392
|
+
return `Error: ${err.message}`;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/chat/session.ts
|
|
397
|
+
var RESET = "\x1B[0m";
|
|
398
|
+
var BOLD = "\x1B[1m";
|
|
399
|
+
var DIM = "\x1B[2m";
|
|
400
|
+
var CYAN = "\x1B[36m";
|
|
401
|
+
var GREEN = "\x1B[32m";
|
|
402
|
+
var YELLOW = "\x1B[33m";
|
|
403
|
+
var BLUE = "\x1B[34m";
|
|
404
|
+
var RED = "\x1B[31m";
|
|
405
|
+
function print(text) {
|
|
406
|
+
process.stdout.write(text + "\n");
|
|
407
|
+
}
|
|
408
|
+
function printBanner(cfg) {
|
|
409
|
+
const modeColor = cfg.mode === "simulation" ? YELLOW : RED;
|
|
410
|
+
const modeLabel = cfg.mode === "simulation" ? "\u{1F7E1} SIMULATION" : "\u{1F534} LIVE";
|
|
411
|
+
print("");
|
|
412
|
+
print(`${BOLD}${CYAN} \u2B21 Moly Terminal${RESET} \u2014 Lido on ${cfg.network}`);
|
|
413
|
+
print(`${DIM} ${modeColor}${modeLabel}${RESET}${DIM} \xB7 ${cfg.ai?.model ?? ""} \xB7 type "exit" to quit${RESET}`);
|
|
414
|
+
print(`${DIM}${"\u2500".repeat(60)}${RESET}`);
|
|
415
|
+
print("");
|
|
416
|
+
}
|
|
417
|
+
async function startChatSession(cfg) {
|
|
418
|
+
if (!cfg.ai) {
|
|
419
|
+
print(`${RED}No AI provider configured. Run: moly setup${RESET}`);
|
|
420
|
+
process.exit(1);
|
|
421
|
+
}
|
|
422
|
+
const { provider, apiKey, model } = cfg.ai;
|
|
423
|
+
const messages = [
|
|
424
|
+
{
|
|
425
|
+
role: "user",
|
|
426
|
+
content: `You are Moly, an AI assistant for interacting with Lido Finance on ${cfg.network}. Current mode: ${cfg.mode} (${cfg.mode === "simulation" ? "dry-run, nothing is broadcast" : "LIVE \u2014 real transactions"}). Help the user stake ETH, manage withdrawals, wrap/unwrap tokens, and participate in governance. Always confirm before executing live transactions. Be concise.`
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
role: "assistant",
|
|
430
|
+
content: `Got it. I'm ready to help you interact with Lido on ${cfg.network} in ${cfg.mode} mode. What would you like to do?`
|
|
431
|
+
}
|
|
432
|
+
];
|
|
433
|
+
printBanner(cfg);
|
|
434
|
+
const rl = readline.createInterface({
|
|
435
|
+
input: process.stdin,
|
|
436
|
+
output: process.stdout,
|
|
437
|
+
terminal: true
|
|
438
|
+
});
|
|
439
|
+
const prompt = () => new Promise((resolve) => {
|
|
440
|
+
rl.question(`${BOLD}${BLUE}you${RESET} \u203A `, resolve);
|
|
441
|
+
});
|
|
442
|
+
while (true) {
|
|
443
|
+
let input;
|
|
444
|
+
try {
|
|
445
|
+
input = (await prompt()).trim();
|
|
446
|
+
} catch {
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
if (!input) continue;
|
|
450
|
+
if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
|
|
451
|
+
print(`${DIM}Goodbye.${RESET}`);
|
|
452
|
+
rl.close();
|
|
453
|
+
process.exit(0);
|
|
454
|
+
}
|
|
455
|
+
messages.push({ role: "user", content: input });
|
|
456
|
+
try {
|
|
457
|
+
while (true) {
|
|
458
|
+
process.stdout.write(`${DIM}thinking...${RESET}\r`);
|
|
459
|
+
const response = await callAi(provider, apiKey, model, messages, TOOL_DEFS);
|
|
460
|
+
process.stdout.write(" ".repeat(20) + "\r");
|
|
461
|
+
messages.push(response.rawAssistantMessage);
|
|
462
|
+
if (response.toolCalls.length > 0) {
|
|
463
|
+
const toolResults = [];
|
|
464
|
+
for (const tc of response.toolCalls) {
|
|
465
|
+
print(`${DIM} \u2699 ${tc.name}(${JSON.stringify(tc.args)})${RESET}`);
|
|
466
|
+
const result = await executeTool(tc.name, tc.args);
|
|
467
|
+
print(`${DIM} \u21B3 ${result.slice(0, 200)}${result.length > 200 ? "\u2026" : ""}${RESET}`);
|
|
468
|
+
toolResults.push(makeToolResultMessage(provider, tc.id, tc.name, result));
|
|
469
|
+
}
|
|
470
|
+
messages.push(...toolResults);
|
|
471
|
+
if (response.text) {
|
|
472
|
+
print(`
|
|
473
|
+
${BOLD}${GREEN}moly${RESET} \u203A ${response.text}
|
|
474
|
+
`);
|
|
475
|
+
}
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
if (response.text) {
|
|
479
|
+
print(`
|
|
480
|
+
${BOLD}${GREEN}moly${RESET} \u203A ${response.text}
|
|
481
|
+
`);
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
} catch (err) {
|
|
486
|
+
print(`${RED}Error: ${err.message}${RESET}`);
|
|
487
|
+
messages.pop();
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
rl.close();
|
|
491
|
+
}
|
|
492
|
+
export {
|
|
493
|
+
startChatSession
|
|
494
|
+
};
|
package/package.json
CHANGED