promptimizer-cli 0.1.25 → 0.1.27
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/bin/promptimizer.mjs +93 -16
- package/package.json +1 -1
package/bin/promptimizer.mjs
CHANGED
|
@@ -190,10 +190,8 @@ function banner(session, version) {
|
|
|
190
190
|
if (hostCount > 1) out(` ${color(ANSI.dim, `${hostCount} hosts merged · router picks across all`)}`);
|
|
191
191
|
out(` ${color(ANSI.dim, `baseline ${baseline}`)}`);
|
|
192
192
|
out();
|
|
193
|
-
out(
|
|
194
|
-
|
|
195
|
-
);
|
|
196
|
-
out(` ${color(ANSI.dim, "Cache keys on full history — /clear then repeat a prompt to see cache hit")}`);
|
|
193
|
+
out(` ${color(ANSI.dim, "Type a prompt, or /help /hosts /models /connect /disconnect /clear /quit")}`);
|
|
194
|
+
out(` ${color(ANSI.dim, "Repeating the same last message hits prompt cache; /clear resets the chat thread")}`);
|
|
197
195
|
out();
|
|
198
196
|
}
|
|
199
197
|
|
|
@@ -302,8 +300,18 @@ function printMeta(result) {
|
|
|
302
300
|
if (meta.provider_id || meta.host) bits.push(String(meta.provider_id || meta.host));
|
|
303
301
|
if (saved != null) bits.push(`saved ${usd(saved)}`);
|
|
304
302
|
if (meta.exact_cache_hit) bits.push(color(ANSI.green, "cache hit"));
|
|
305
|
-
else if (meta.
|
|
303
|
+
else if (meta.prompt_cache_hit) bits.push(color(ANSI.green, "prompt cache"));
|
|
304
|
+
else if (meta.semantic_cache_hit) {
|
|
305
|
+
const mode = meta.semantic_cache_mode === "full" ? "semantic full" : meta.semantic_cache_mode === "prompt" ? "prompt cache" : "semantic hybrid";
|
|
306
|
+
const sim =
|
|
307
|
+
meta.semantic_similarity != null ? ` ${Math.round(Number(meta.semantic_similarity) * 100)}%` : "";
|
|
308
|
+
bits.push(color(ANSI.green, `${mode}${sim}`));
|
|
309
|
+
} else if (meta.prefix_cache_hit) bits.push(color(ANSI.green, "prefix cache"));
|
|
306
310
|
else if ("cache_hit" in meta) bits.push(color(ANSI.gray, "miss"));
|
|
311
|
+
if (meta.quality_gate) bits.push(`gate:${meta.quality_gate}`);
|
|
312
|
+
if (meta.quality_audit) {
|
|
313
|
+
bits.push(meta.quality_audit_pass === false ? color(ANSI.yellow, "audit fail") : "audit ok");
|
|
314
|
+
}
|
|
307
315
|
if (meta.escalated) bits.push(meta.escalation_reason ? `escalated:${meta.escalation_reason}` : "escalated");
|
|
308
316
|
if (meta.latency_ms != null) bits.push(`${Math.round(Number(meta.latency_ms))}ms`);
|
|
309
317
|
out(color(ANSI.dim, ` ↳ ${bits.join(" · ")}`));
|
|
@@ -321,6 +329,76 @@ async function complete(flags, config, messages) {
|
|
|
321
329
|
});
|
|
322
330
|
}
|
|
323
331
|
|
|
332
|
+
/** Stream a completion; writes tokens to stdout as they arrive. Returns { text, result }. */
|
|
333
|
+
async function completeStream(flags, config, messages) {
|
|
334
|
+
const gatewayURL = gateway(flags, config);
|
|
335
|
+
const { apiKey, sessionId } = authFromConfig(flags, config);
|
|
336
|
+
const headers = { "content-type": "application/json" };
|
|
337
|
+
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
|
|
338
|
+
else if (sessionId) {
|
|
339
|
+
headers.authorization = `Bearer ${sessionId}`;
|
|
340
|
+
headers["x-promptimizer-session"] = sessionId;
|
|
341
|
+
}
|
|
342
|
+
const response = await fetch(`${gatewayURL}/v1/chat/completions`, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers,
|
|
345
|
+
body: JSON.stringify({ messages, stream: true }),
|
|
346
|
+
});
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
const data = await response.json().catch(() => ({}));
|
|
349
|
+
const detail =
|
|
350
|
+
typeof data === "object" && data && "detail" in data ? String(data.detail) : response.statusText;
|
|
351
|
+
throw Object.assign(new Error(detail), { status: response.status });
|
|
352
|
+
}
|
|
353
|
+
if (!response.body) {
|
|
354
|
+
const data = await response.json();
|
|
355
|
+
return { text: data.choices?.[0]?.message?.content?.trim() ?? "", result: data };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const reader = response.body.getReader();
|
|
359
|
+
const decoder = new TextDecoder();
|
|
360
|
+
let buffer = "";
|
|
361
|
+
let text = "";
|
|
362
|
+
let result = {
|
|
363
|
+
model: undefined,
|
|
364
|
+
usage: undefined,
|
|
365
|
+
promptimizer: undefined,
|
|
366
|
+
choices: [{ message: { role: "assistant", content: "" } }],
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
while (true) {
|
|
370
|
+
const { done, value } = await reader.read();
|
|
371
|
+
if (done) break;
|
|
372
|
+
buffer += decoder.decode(value, { stream: true });
|
|
373
|
+
const parts = buffer.split("\n");
|
|
374
|
+
buffer = parts.pop() ?? "";
|
|
375
|
+
for (const line of parts) {
|
|
376
|
+
const trimmed = line.trim();
|
|
377
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
378
|
+
const data = trimmed.slice(5).trim();
|
|
379
|
+
if (!data) continue;
|
|
380
|
+
if (data === "[DONE]") continue;
|
|
381
|
+
try {
|
|
382
|
+
const parsed = JSON.parse(data);
|
|
383
|
+
if (parsed.error?.message) throw new Error(parsed.error.message);
|
|
384
|
+
const delta = parsed.choices?.[0]?.delta?.content;
|
|
385
|
+
if (delta) {
|
|
386
|
+
text += delta;
|
|
387
|
+
process.stdout.write(delta);
|
|
388
|
+
}
|
|
389
|
+
if (parsed.promptimizer) result.promptimizer = parsed.promptimizer;
|
|
390
|
+
if (parsed.usage) result.usage = parsed.usage;
|
|
391
|
+
if (parsed.model) result.model = parsed.model;
|
|
392
|
+
} catch (err) {
|
|
393
|
+
if (err instanceof Error && err.message && !err.message.includes("JSON")) throw err;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
result.choices = [{ message: { role: "assistant", content: text } }];
|
|
399
|
+
return { text, result };
|
|
400
|
+
}
|
|
401
|
+
|
|
324
402
|
async function cmdLogin(flags) {
|
|
325
403
|
const apiKey = flags.key || flags.k || process.env.PROMPTIMIZER_API_KEY;
|
|
326
404
|
if (!apiKey) die("Missing --key. Create one at /account.");
|
|
@@ -457,10 +535,11 @@ async function cmdChat(flags, positional) {
|
|
|
457
535
|
const config = readConfig();
|
|
458
536
|
const prompt = String(flags.prompt || positional.join(" ")).trim();
|
|
459
537
|
if (!prompt) die('Usage: promptimizer chat "What is 17 * 24?"');
|
|
460
|
-
const result = await complete(flags, config, [{ role: "user", content: prompt }]);
|
|
461
|
-
const text = result.choices?.[0]?.message?.content?.trim() ?? "";
|
|
462
538
|
out();
|
|
463
|
-
out(
|
|
539
|
+
out(color(ANSI.magenta, "✦"));
|
|
540
|
+
const { text, result } = await completeStream(flags, config, [{ role: "user", content: prompt }]);
|
|
541
|
+
if (!text) process.stdout.write(color(ANSI.dim, "(empty)"));
|
|
542
|
+
process.stdout.write("\n");
|
|
464
543
|
out();
|
|
465
544
|
printMeta(result);
|
|
466
545
|
out();
|
|
@@ -665,20 +744,18 @@ async function interactive(flags) {
|
|
|
665
744
|
}
|
|
666
745
|
|
|
667
746
|
history.push({ role: "user", content: trimmed });
|
|
668
|
-
|
|
747
|
+
out();
|
|
748
|
+
out(color(ANSI.magenta, "✦"));
|
|
669
749
|
try {
|
|
670
|
-
const result = await
|
|
671
|
-
process.stdout.write("
|
|
672
|
-
|
|
750
|
+
const { text, result } = await completeStream(flags, readConfig(), history);
|
|
751
|
+
if (!text) process.stdout.write(color(ANSI.dim, "(empty)"));
|
|
752
|
+
process.stdout.write("\n");
|
|
673
753
|
history.push({ role: "assistant", content: text });
|
|
674
754
|
out();
|
|
675
|
-
out(color(ANSI.magenta, "✦"));
|
|
676
|
-
out(text);
|
|
677
|
-
out();
|
|
678
755
|
printMeta(result);
|
|
679
756
|
out();
|
|
680
757
|
} catch (error) {
|
|
681
|
-
process.stdout.write("
|
|
758
|
+
process.stdout.write("\n");
|
|
682
759
|
history.pop();
|
|
683
760
|
out(color(ANSI.yellow, ` ${error instanceof Error ? error.message : String(error)}`));
|
|
684
761
|
out();
|