agent-clinch 0.7.6 → 0.7.7
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/cli.js +35 -16
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -205,6 +205,7 @@ function downloadFile(url, dest) {
|
|
|
205
205
|
async function promptAI(systemPrompt, userText, cfg) {
|
|
206
206
|
if (cfg.engine === 'ollama') {
|
|
207
207
|
try {
|
|
208
|
+
console.log(c.dim(`\n[Agent Q] Dispatching request to local Ollama (${cfg.ollamaModel || 'llama3'})...`));
|
|
208
209
|
const res = await fetch('http://127.0.0.1:11434/api/chat', {
|
|
209
210
|
method: 'POST',
|
|
210
211
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -233,6 +234,8 @@ async function promptAI(systemPrompt, userText, cfg) {
|
|
|
233
234
|
await downloadFile(cfg.ggufUrl || "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF/resolve/main/qwen2.5-1.5b-instruct-q4_k_m.gguf", resolvedPath);
|
|
234
235
|
}
|
|
235
236
|
|
|
237
|
+
console.log(c.dim(`\n[Agent Q] Loading GGUF model into memory (this may take a few seconds)...`));
|
|
238
|
+
|
|
236
239
|
let nodeLlama;
|
|
237
240
|
try { nodeLlama = await import('node-llama-cpp'); }
|
|
238
241
|
catch (e) {
|
|
@@ -250,6 +253,8 @@ async function promptAI(systemPrompt, userText, cfg) {
|
|
|
250
253
|
chatWrapper: new nodeLlama.ChatMLChatWrapper()
|
|
251
254
|
});
|
|
252
255
|
|
|
256
|
+
console.log(c.dim(`[Agent Q] Model loaded. Analyzing intent...`));
|
|
257
|
+
|
|
253
258
|
let responseText = "";
|
|
254
259
|
await session.prompt(userText, { maxTokens: 1500, onTextChunk: (chunk) => { responseText += chunk; } });
|
|
255
260
|
return responseText;
|
|
@@ -257,24 +262,42 @@ async function promptAI(systemPrompt, userText, cfg) {
|
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
async function parseIntentWithLLM(userInput, cfg) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
const systemPrompt = `You are a structured data extractor for a purchasing agent.
|
|
266
|
+
Analyze the user's input.
|
|
267
|
+
|
|
268
|
+
If the user says a greeting (like "hi" or "hello") or does not clearly specify BOTH an item and a budget, output EXACTLY this JSON:
|
|
269
|
+
{"error": "Please specify what you want to buy and your maximum budget (e.g. 'Get me a laptop for under $500')."}
|
|
263
270
|
|
|
264
|
-
JSON
|
|
271
|
+
If they DO specify a purchase intent, output EXACTLY this JSON schema:
|
|
265
272
|
{
|
|
266
273
|
"intent": "purchase",
|
|
267
|
-
"category": "string (e.g.
|
|
268
|
-
"item": "string (the
|
|
269
|
-
"max_budget": number (
|
|
270
|
-
}
|
|
274
|
+
"category": "string (e.g. electronics, domain_names, software, etc)",
|
|
275
|
+
"item": "string (the actual item requested)",
|
|
276
|
+
"max_budget": number (integer representing the max budget)
|
|
277
|
+
}
|
|
278
|
+
Your response MUST be ONLY valid JSON. Do not include conversational text.`;
|
|
271
279
|
|
|
272
280
|
try {
|
|
273
281
|
const rawRes = await promptAI(systemPrompt, userInput, cfg);
|
|
274
282
|
const cleanJson = rawRes.replace(/```json|```/g, "").trim();
|
|
275
|
-
|
|
283
|
+
|
|
284
|
+
const parsed = JSON.parse(cleanJson);
|
|
285
|
+
|
|
286
|
+
// Check if the LLM flagged the input as a greeting/unclear
|
|
287
|
+
if (parsed.error) {
|
|
288
|
+
console.log(c.yellow(`\n[Agent Q] ${parsed.error}`));
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Fallback validation to ensure it didn't hallucinate missing fields
|
|
293
|
+
if (!parsed.item || !parsed.max_budget) {
|
|
294
|
+
console.log(c.yellow(`\n[Agent Q] I couldn't quite figure out the item or budget from your request. Please be specific!`));
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return parsed;
|
|
276
299
|
} catch (e) {
|
|
277
|
-
console.error(c.red("Failed to parse intent. Falling back to manual entry."));
|
|
300
|
+
console.error(c.red("\n[Agent Q] Failed to parse intent correctly. Falling back to manual entry."));
|
|
278
301
|
return null;
|
|
279
302
|
}
|
|
280
303
|
}
|
|
@@ -408,7 +431,7 @@ program
|
|
|
408
431
|
|
|
409
432
|
const parsed = await parseIntentWithLLM(naturalIntent, cfg);
|
|
410
433
|
if (!parsed) {
|
|
411
|
-
|
|
434
|
+
// We failed to parse correctly (or the user typed hi), gracefully exit rather than crashing
|
|
412
435
|
process.exit(1);
|
|
413
436
|
}
|
|
414
437
|
|
|
@@ -423,7 +446,7 @@ program
|
|
|
423
446
|
constraints = parsed;
|
|
424
447
|
budget = parsed.max_budget;
|
|
425
448
|
|
|
426
|
-
console.log(c.dim(`\
|
|
449
|
+
console.log(c.dim(`\n[Network] Querying registry for category "${parsed.category}"...`));
|
|
427
450
|
const coreDiscovery = getClinchCore(cfg);
|
|
428
451
|
await coreDiscovery.initialize(cfg.token);
|
|
429
452
|
const results = await coreDiscovery.search(parsed.category);
|
|
@@ -483,10 +506,7 @@ program
|
|
|
483
506
|
return;
|
|
484
507
|
}
|
|
485
508
|
|
|
486
|
-
// Ask the core to build the context prompt, but evaluate it HERE in the CLI
|
|
487
509
|
const promptStr = core.buildAgentPrompt(sessionId, incomingMessage);
|
|
488
|
-
console.log(c.dim(`\n[Agent Q] Evaluating turn ${session.currentTurn} with ${cfg.engine}...`));
|
|
489
|
-
|
|
490
510
|
const aiResponse = await promptAI(promptStr, incomingMessage, cfg);
|
|
491
511
|
|
|
492
512
|
let price = null;
|
|
@@ -635,7 +655,6 @@ program
|
|
|
635
655
|
console.log(c.yellow(`\nRehydrating Session ${c.bold(sessionId)}...\n`));
|
|
636
656
|
if (opts.auto) {
|
|
637
657
|
cfg = await ensureAIEngine(cfg);
|
|
638
|
-
// ... hook auto logic here if needed (omitted for brevity, handled heavily in negotiate)
|
|
639
658
|
}
|
|
640
659
|
|
|
641
660
|
const core = getClinchCore(cfg);
|